library(ggplot2)
library(reshape2)
library(gridExtra)
library(scales)
source("../Rscripts/BaseScripts.R")
library(data.table)

1 Using bedtools to extract the number of mapped reas per 1k-window per population

1.1 Create bed files with 1k windows

chsize<-read.table("../Data/new_vcf/chr_sizes.bed")

#Prevent scientific notation in bed files
options(scipen=999)
library(DataCombine)

for (i in 1:26){
    l<-chsize$V3[i]
    ends<-seq(1000,l, by=1000)
    start<-seq(1,l, by=1000) 
   
    new<-data.frame(ch=paste0("chr",i), st=start,en=c(ends, l))
    new<-InsertRow(new,c("track=e=bedGrapph", '', ''), 1)
    write.table(new, paste0("../Data/bam_depth/bed1k/chr",i,"_1k.bed"), row.names = F, col.names = F, quote = F, sep = "\t")
}

1.2 Creat bash scripts to sort and index bam files

pops_info<-read.csv("../Data/Sample_metadata_892pops.csv")
pops<-unique(pops_info$Population.Year)


for (i in 1: length(pops)){
    df<-pops_info[pops_info$Population.Year==pops[i],]
    sink(paste0("../Data/Slurmscripts/sort_bam_", pops[i],".sh"))
    cat("#!/bin/bash -l\n")
    cat(paste0("#SBATCH --job-name=sort",pops[i]," \n"))
    cat(paste0("#SBATCH --mem=16G \n")) 
    cat(paste0("#SBATCH --ntasks=8 \n")) 
    cat(paste0("#SBATCH -e =sort",pops[i],".err  \n"))
    cat(paste0("#SBATCH --time=200:00:00  \n"))
    cat(paste0("#SBATCH -p high  \n"))
    cat("\n\n")
    cat("module load samtools \n\n") 
         
    for (j in 1:nrow(df)){
        cat(paste0("samtools sort /home/eoziolor/phpopg/data/align/",df$Sample[j],".bam -o /home/ktist/ph/data/bam/",df$Sample[j],"_sorted.bam \n"))
        cat(paste0("samtools index /home/ktist/ph/data/bam/",df$Sample[j],"_sorted.bam \n"))
    }
    sink(NULL)
}


for (i in 1: length(pops)){
    df<-pops_info[pops_info$Population.Year==pops[i],]
    sink(paste0("../Data/Slurmscripts/bedtools_count_", pops[i],".sh"))
    cat("#!/bin/bash -l\n")
    cat(paste0("#SBATCH --job-name=ct",pops[i]," \n"))
    cat(paste0("#SBATCH --mem=16G \n")) 
    cat(paste0("#SBATCH --ntasks=8 \n")) 
    cat(paste0("#SBATCH -e =ct",pops[i],".err  \n"))
    cat(paste0("#SBATCH --time=240:00:00  \n"))
    cat(paste0("#SBATCH -p high  \n"))
    cat("\n\n")
    cat("module load bedtools \n\n") 
    
    for (c in 1:26){
        cat(paste0("bedtools multicov -bams "))
        for (j in 1: nrow(df)){
            cat(paste0("/home/ktist/ph/data/bam/",df$Sample[j] , "_sorted.bam "))
        }
        cat(paste0("-bed /home/ktist/ph/data/bam_depth/chr",c,"_1k.bed > /home/ktist/ph/data/coverage/",pops[i],"_chr",c,".txt \n"))
    }
    sink(NULL)

}

1.3 Calculated the normalized number of mapped reads (based on the total count of reads)

  • Located in Data/bam_depth/ReadNumbers/
pops_info<-read.csv("../Data/Sample_metadata_892pops.csv")
pops<-unique(pops_info$Population.Year)

## Get the total raw read count per sample from each bam file
sink("../Data/Slurmscripts/Raw_total_read_count.sh")
cat("#!/bin/bash -l\n")
cat(paste0("#SBATCH --job-name=totalRead \n"))
cat(paste0("#SBATCH --mem=16G \n")) 
cat(paste0("#SBATCH --ntasks=8 \n")) 
cat(paste0("#SBATCH -e =totalRead.err  \n"))
cat(paste0("#SBATCH --time=240:00:00  \n"))
cat(paste0("#SBATCH -p high  \n"))
cat("\n\n")
cat("module load samtools \n\n") 

for (j in 1:nrow(pops_info)){
    cat(paste0("samtools view -c -F 260 ", "/home/ktist/ph/data/bam/", pops_info$Sample[j], "_sorted.bam > ", pops_info$Sample[j],"_count.txt \n"))
    }
sink(NULL)


# Compile the files into one
rfiles<-list.files("../Data/bam_depth/RawTotal/")
rawTotal<-data.frame(sample=rfiles)
for (i in 1: length(rfiles)){
    df<-read.table(paste0("../Data/bam_depth/RawTotal/",rfiles[i]))
    fname<-gsub("_count.txt", '',rfiles[i])
    rawTotal$sample[i]<-fname
    rawTotal$pop[i]<-pops_info$Population.Year[pops_info$Sample==fname]
    rawTotal$rawTotal[i]<-df$V1[1]
}
write.csv(rawTotal, "../Output/CNV/rawReadTotalCount_perSample.csv", row.names = F)

for (i in 1:length(pops)){
    pop<-pops[i]
    popdf<-pops_info[pops_info$Population.Year==pop,]
    n<-nrow(popdf)
    for(j in 1:26){
        #read the mapped read number file
        df<-read.table(paste0("../Data/bam_depth/ReadNumbers/",pop,"_chr",j,".txt"))
        # normalized by the total read count 
        df2<-df[,4:ncol(df)]/rawTotal$rawTotal[rawTotal$pop==pop]*10^7
        # calculate average
        df2$mean<-rowMeans(df2)
        reads<-cbind(df[,1:3],df2)
        write.csv(reads, paste0("../Output/CNV/ReadNumber_normalized_",pop,"_chr",j,'.csv'), row.names = F)
    }
}


# create a summary of total read count file for record
for (c in 1:26){
    total<-data.frame()
    for (i in 1: length(pops)){
        pop<-pops[i]
        popdf<-read.csv(paste0("../Output/CNV/ReadNumber_normalized_",pop, "_chr",c,".csv"))
        popdf<-popdf[,c(1:3, ncol(popdf))]
        popdf$pop<-pop
        total<-rbind(total, popdf)
    }
    write.csv(total, paste0("../Output/CNV/Chr",c,"_meanReadCount_perPop.csv"))
}

# Visualize the output
#ex. chr1
#c1<-read.csv("../Output/CNV/Chr1_meanReadCount_perPop.csv", row.names = 1)
#ggplot(total[total$V3<1000000,], aes(x=V3, y=mean, color=pop))+
#        geom_point(size=.5)
#

2 Compare the normalized read counts per 1k window between populations

2.1 1. PWS between years

2.1.1 Plot the overlapping regions between population pairs to look for candidate regions

pws<-c("PWS91","PWS96","PWS07","PWS17")
comb<-t(combn(pws,2))

Plots<-list()
for (c in 1:26){
    Results<-data.frame()
    for (i in 1:nrow(comb)){
        pop1<-comb[i,1]
        pop2<-comb[i,2]
        n1<-nrow(pops_info[pops_info$Population.Year==pop1,])
        n2<-nrow(pops_info[pops_info$Population.Year==pop2,])
        
        df1<-read.csv(paste0("../Output/CNV/ReadNumber_normalized_",pop1, "_chr",c,".csv"))
        df2<-read.csv(paste0("../Output/CNV/ReadNumber_normalized_",pop2, "_chr",c,".csv"))
        combdf<-cbind(df1[,4:(ncol(df1)-1)],df2[,4:(ncol(df2)-1)])
        wilcoxResults<-apply(combdf, 1, function(x){ wilcox.test(x[1:n1],x[(n1+1):(n1+n2)]) })
        sig<-lapply(wilcoxResults,function(x) {x<-unlist(x)
                                        p<-unname(x[2])
                                        return(as.numeric(p)) })
        #add row numbers to find consecutive windows
        df1$number<-1:nrow(df1)
        df2$number<-1:nrow(df2)
        #calculate SD for plotting
        df1$sd<-apply(df1[,c(4:(n1+3))], 1, sd)
        df2$sd<-apply(df2[,c(4:(n2+3))], 1, sd)
        
        test<-df1[,c("number","V1","V2","V3")]    
        test$p.value<-unlist(sig)
        test<-test[test$p.value<=0.01,]
        re1<-merge(test, df1[,c("number","V1","V2","V3","mean","sd")])
        re2<-merge(test, df2[,c("number","V1","V2","V3","mean","sd")])
        re1$pop<-pop1
        re2$pop<-pop2
        results<-rbind(re1,re2)
        
        # Find consecutive windows
        re1<-re1[order(re1$number),]
        breaks<-c(0, which(diff(re1$number) != 1),length(re1$number))
        runpos<-sapply(seq(length(breaks)-1),
               function(x) re1$number[(breaks[x]+1):breaks[x+1]])
        runpos3<-Filter(function(x) any(length(unlist(x))>=5), runpos)
        
        # filter the results to only consecutive positions
        if(length(runpos3)>0){
            positions<-unlist(runpos3)
            results<-results[results$number %in% positions,]
            results$comp<-paste0(pop1,"_",pop2)
            Results<-rbind(Results, results)
            write.csv(Results, paste0("../Output/CNV/pairComp/runOver5k.in.chr",c,".csv"))
        }
    }
    
    
    ovlap<-as.data.frame.matrix(table(Results$number, Results$comp))
    ovlap<-ovlap/2
    ovlap$sum<-rowSums(ovlap)
    ovlap<-ovlap[ovlap$sum>=2,]
    ovlap$number<-as.integer(rownames(ovlap))
    
    ovlap<-merge(ovlap, re1[,c("number","V2")], by="number")
    write.csv(ovlap,paste0("../Output/CNV/pairComp/Overlapping.positions.runOver5k.chr",c,".csv"))
    plots[[c]]<-ggplot(ovlap, aes(x=V2, y=sum))+
        geom_point(size=0.6, color="steelblue")+
        ggtitle(paste0("Chr",c))+
        xlab("")+ylab("No. of population pairs")+
        scale_y_continuous(breaks = seq(2, max(ovlap$sum), by = 1))+
            theme_light()+
        scale_x_continuous(breaks=seq(0, max(re1$V2), by=5000000), labels=comma)+
        theme(panel.grid.minor.y=element_blank())
}


 {pdf(paste0("../Output/CNV/pairComp/overlapping_windows_PWS.pdf"), width = 12, height = 30)
        do.call(grid.arrange, c(plots, ncol=1))
        dev.off()}

2.1.2 Plot the regions with P<0.01 for >5 windows per pair

# Run Wilcoxon test and extract the sites with P<0.01 over 5 windows (5k)
# Create a pair table 
pws<-c("PWS91","PWS96","PWS07","PWS17")
comb<-t(combn(pws,2))
#reorder the comb
comb<-comb[c(1,4,6,2,3,5),]

#chromossome size
chsize<-read.table("../Data/new_vcf/chr_sizes.bed")

# name the colors
colors<-cols[c(1,2,3,5)]
names(colors)<-pws

for (c in 1:26){
    plotlist<-list()
    for (i in 1:nrow(comb)){
        pop1<-comb[i,1]
        pop2<-comb[i,2]
        n1<-nrow(pops_info[pops_info$Population.Year==pop1,])
        n2<-nrow(pops_info[pops_info$Population.Year==pop2,])
        
        df1<-read.csv(paste0("../Output/CNV/ReadNumber_normalized_",pop1, "_chr",c,".csv"))
        df2<-read.csv(paste0("../Output/CNV/ReadNumber_normalized_",pop2, "_chr",c,".csv"))
        combdf<-cbind(df1[,4:(ncol(df1)-1)],df2[,4:(ncol(df2)-1)])
        wilcoxResults<-apply(combdf, 1, function(x){ wilcox.test(x[1:n1],x[(n1+1):(n1+n2)]) })
        sig<-lapply(wilcoxResults,function(x) {x<-unlist(x)
                                        p<-unname(x[2])
                                        return(as.numeric(p)) })
        #add row numbers to find consecutive windows
        df1$number<-1:nrow(df1)
        df2$number<-1:nrow(df2)
        #calculate SD for plotting
        df1$sd<-apply(df1[,c(4:(n1+3))], 1, sd)
        df2$sd<-apply(df2[,c(4:(n2+3))], 1, sd)
        
        test<-df1[,c("number","V1","V2","V3")]    
        test$p.value<-unlist(sig)
        test<-test[test$p.value<=0.01,]
        re1<-merge(test, df1[,c("number","V1","V2","V3","mean","sd")])
        re2<-merge(test, df2[,c("number","V1","V2","V3","mean","sd")])
        re1$pop<-pop1
        re2$pop<-pop2
        results<-rbind(re1,re2)
        
        # Find consecutive windows
        re1<-re1[order(re1$number),]
        breaks<-c(0, which(diff(re1$number) != 1),length(re1$number))
        runpos<-sapply(seq(length(breaks)-1),
               function(x) re1$number[(breaks[x]+1):breaks[x+1]])
        runpos3<-Filter(function(x) any(length(unlist(x))>=5), runpos)
        #saveRDS(runpos3,file=paste0("../Output/CNV/pairComp/chr",c,"_",pop1,".",pop2,"_consecutiveWindows.RData"))
        # filter the results to only consective positions
        positions<-unlist(runpos3)
        results<-results[results$number %in% positions,]
        
        colpairs<-colors[c(pop1,pop2)]
        results$pop<-factor(results$pop, levels=pws)
        plotlist[[i]]<-ggplot(results, aes(x=V2, y=mean, color=pop))+
            geom_point(size=1, position=position_dodge(width = 1))+
            geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd),position=position_dodge(width = 3), width=0.3, size=0.2)+
            ggtitle(paste0("Chr",c," ", pop1,"-",pop2))+
            xlab("")+ylab("normalized mean read count per 1k")+
            theme(legend.title = element_blank())+xlim(0,chsize$V3[c])+
            scale_color_manual(values=paste0(colpairs, "66"))+
            theme_bw()
        
    
    }
    
    {pdf(paste0("../Output/CNV/pairComp/chr",c,"_PWS_5windows.pdf"), width = 12, height = 16)
    do.call(grid.arrange, c(plotlist, ncol=1))
    dev.off()}
    
}
  • Chr 1

2.1.3 Look at the bam files for the candidate loci

# Start with windows with significant read numbers difference in multiple population pairs
#Prevent scientific notation in bed files
options(scipen=999)

nobuffer<-data.frame(chr="chr",start="start",end="end")
bedfile<-data.frame(chr="chr",start="start",end="end")

for (i in 1:26){
    df<-read.csv(paste0("../Output/CNV/pairComp/Overlapping.positions.runOver5k.chr",i,".csv"))
    df<-df[df$sum>=4,]
    
    if (nrow(df)>0){
        breaks<-c(0, which(diff(df$number) != 1),length(df$number))
        runpos<-sapply(seq(length(breaks)-1),
               function(x) df$number[(breaks[x]+1):breaks[x+1]])
        
        if (is.list(runpos)) {
            runpos<-Filter(function(x) any(length(unlist(x))>=5), runpos)
            for (j in 1:length(runpos)){
                pos<-runpos[j]
                pos<-unlist(pos)
                #no buffer bedfile
                bed1<-data.frame(chr=paste0("chr",i), start=df$V2[df$number==pos[1]], end=df$V2[df    $number==pos[length(pos)]]+999)
                nobuffer<-rbind(nobuffer, bed1)               
                # add 50k buffer around the bed files
                bed<-data.frame(chr=paste0("chr",i), start=df$V2[df$number==pos[1]], end=df$V2[df    $number==pos[length(pos)]]+999+50000)
                if (bed$start[1]<50000) bed$start[1]<-0
                if (bed$start[1]>=50000) bed$start[1]<-bed$start[1]-50000
                
                bedfile<-rbind(bedfile,bed)
            }
        
        }
        
        if (!is.list(runpos)){
            if (nrow(runpos)>=5){
                bed<-data.frame(chr=paste0("chr",i), start=runpos[1,1], end=runpos[nrow(runpos),1]+999+50000)
                if (bed$start[1]<50000) bed$start[1]<-0
                if (bed$start[1]>=50000) bed$start[1]<-bed$start[1]-50000
                bedfile<-rbind(bedfile,bed)
                bed1<-data.frame(chr=paste0("chr",i), start=runpos[1,1], end=runpos[nrow(runpos),1]+999)
                nobuffer<-rbind(nobuffer, bed1)    
                
            }
            
        }
        
        
    }
}
bedfile<-bedfile[-1,]
write.table(bedfile, "../Output/CNV/pairComp/PWS_4overlap_regions.bed", row.names=F, col.names=F,quote=F, sep="\t")
nobuffer<-nobuffer[-1,]
write.table(nobuffer, "../Output/CNV/pairComp/PWS_4overlap_regions_noBuffer.bed", row.names=F, col.names=F,quote=F, sep="\t")
 

   
#create a slurm script file to extract regions to visualize

pws96<-pops_info$Sample[pops_info$Population.Year=="PWS96"]
pws91<-pops_info$Sample[pops_info$Population.Year=="PWS91"]
pws07<-pops_info$Sample[pops_info$Population.Year=="PWS07"]
pws17<-pops_info$Sample[pops_info$Population.Year=="PWS17"]

sink("../Data/Slurmscripts/Extract_Depth_PWS.sh")
cat("#!/bin/bash -l")
cat("\n")
cat(paste0("#SBATCH --job-name=DepthPWS \n"))
cat(paste0("#SBATCH --mem=16G \n")) 
cat(paste0("#SBATCH --ntasks=1 \n")) 
cat(paste0("#SBATCH -e Extract_Depth1.err  \n"))
cat(paste0("#SBATCH --time=144:00:00  \n"))
cat(paste0("#SBATCH --mail-user=ktist@ucdavis.edu ##email you when job starts,ends,etc \n"))
cat(paste0("#SBATCH --mail-type=ALL \n"))
cat(paste0("#SBATCH -p high  \n"))
cat("\n\n")
cat("module load samtools \n") 

for (i in 1:20){
    cat(paste0("samtools depth -b /home/ktist/ph/data/bam_depth/PWS_4overlap_regions.bed /home/ktist/ph/data/bam/", pws91[i],"_sorted.bam > /home/ktist/ph/data/bam_depth/PWS/",pws91[i],"_overlapRegions.txt \n"))
    cat(paste0("gzip /home/ktist/ph/data/bam_depth/PWS/",pws91[i],"_overlapRegions.txt \n"))
    
    cat(paste0("samtools depth -b /home/ktist/ph/data/bam_depth/PWS_4overlap_regions.bed /home/ktist/ph/data/bam/", pws96[i],"_sorted.bam > /home/ktist/ph/data/bam_depth/PWS/",pws96[i],"_overlapRegions.txt \n"))
    cat(paste0("gzip /home/ktist/ph/data/bam_depth/PWS/",pws96[i],"_overlapRegions.txt \n"))
    
    cat(paste0("samtools depth -b /home/ktist/ph/data/bam_depth/PWS_4overlap_regions.bed /home/ktist/ph/data/bam/", pws07[i],"_sorted.bam > /home/ktist/ph/data/bam_depth/PWS/",pws07[i],"_overlapRegions.txt \n"))
    cat(paste0("gzip /home/ktist/ph/data/bam_depth/PWS/",pws07[i],"_overlapRegions.txt \n"))
     cat(paste0("samtools depth -b /home/ktist/ph/data/bam_depth/PWS_4overlap_regions.bed /home/ktist/ph/data/bam/", pws17[i],"_sorted.bam > /home/ktist/ph/data/bam_depth/PWS/",pws17[i],"_overlapRegions.txt \n"))
    cat(paste0("gzip /home/ktist/ph/data/bam_depth/PWS/",pws17[i],"_overlapRegions.txt \n"))
}
sink(NULL)

#plot the results per regions


pwslist<-c("pws91","pws96","pws07","pws17")

nobuffer<-read.table("../Output/CNV/pairComp/PWS_4overlap_regions_noBuffer.bed", sep="\t")
bedfile<-read.table("../Output/CNV/pairComp/PWS_4overlap_regions.bed", sep="\t")

totalreads<-read.csv("../Output/CNV/rawReadTotalCount_perSample.csv")

for (j in 1:length(pwslist)){
    plist<-get(paste0(pwslist[j]))
    depth_list<-list()
    for (i in 1:20){
        df<-fread(paste0("../Data/bam_depth/PWS_overlap/",plist[i],"_overlapRegions.txt.gz"))
        
        reads<-list()
        for (b in 1: nrow(bedfile)){
            dp<-df[V1==bedfile$V1[b]& V2>=bedfile$V2[b] & V2<= bedfile$V3[b]]
            dp$sample<-plist[i]
            reads[[b]]<-dp
        }
        depth_list[[i]]<-reads
        names(depth_list)[i]<-plist[i]
    }
    #saveRDS(depth_list,file=paste0("../Output/CNV/pairComp/PWS_overlap_individual_depth/", pwslist[j],"_depths.RData"))
    
    for (b in 1: nrow(bedfile)){
        data<-lapply(depth_list, '[[', b)
        depths<-do.call(rbind,data)
        ggplot(depths, aes(x=V2, y=V3))+
            facet_wrap(~sample, ncol=4)+
            geom_point(size=0.3, alpha=0.4, color="blue")+
            ylab("Read depth")+xlab("")+theme_bw()+
            theme(panel.grid = element_blank())+ylim(0,30)+
            ggtitle(paste0(bedfile$V1[b]," ",nobuffer$V2[b],"-",nobuffer$V3[b]))+
            geom_vline(xintercept = nobuffer$V2[b], color="gray70", size=0.3)+
            geom_vline(xintercept = nobuffer$V3[b], color="gray70", size=0.3)
        ggsave(paste0("../Output/CNV/pairComp/PWS_overlap_individual_depth/region_",b,"_",pwslist[j],".png"), width = 12, height=9, dpi=300)
        }
    }
    
        
}
        
depth_list<-readRDS(file="../Output/CNV/pairComp/PWS_overlap_individual_depth/pws91_depths.RData")
j=1

for (b in 2: nrow(bedfile)){
        data<-lapply(depth_list, '[[', b)
        depths<-do.call(rbind,data)
        ggplot(depths, aes(x=V2, y=V3))+
            facet_wrap(~sample, ncol=4)+
            geom_point(size=0.3, alpha=0.4, color="blue")+
            ylab("Read depth")+xlab("")+theme_bw()+
            theme(panel.grid = element_blank())+ylim(0,30)+
            ggtitle(paste0(bedfile$V1[b]," ",nobuffer$V2[b],"-",nobuffer$V3[b]))+
            geom_vline(xintercept = nobuffer$V2[b], color="gray70", size=0.3)+
            geom_vline(xintercept = nobuffer$V3[b], color="gray70", size=0.3)
        ggsave(paste0("../Output/CNV/pairComp/PWS_overlap_individual_depth/region_",b,"_",pwslist[j],".png"), width = 12, height=9, dpi=300)
        }

2.2 2. Year 2017 population comparison

2.3 1. PWS between years

2.3.1 Plot the overlapping regions between population pairs to look for candidate regions

# Year2017 populations
y17<-c("TB17","PWS17","SS17","BC17","WA17","CA17")
comb2<-t(combn(y17,2))


plots<-list()
for (c in 2:26){
    Results<-data.frame()
    for (i in 1:nrow(comb2)){
        pop1<-comb2[i,1]
        pop2<-comb2[i,2]
        n1<-nrow(pops_info[pops_info$Population.Year==pop1,])
        n2<-nrow(pops_info[pops_info$Population.Year==pop2,])
        
        df1<-read.csv(paste0("../Output/CNV/ReadNumber_normalized_",pop1, "_chr",c,".csv"))
        df2<-read.csv(paste0("../Output/CNV/ReadNumber_normalized_",pop2, "_chr",c,".csv"))
        combdf<-cbind(df1[,4:(ncol(df1)-1)],df2[,4:(ncol(df2)-1)])
        wilcoxResults<-apply(combdf, 1, function(x){ wilcox.test(x[1:n1],x[(n1+1):(n1+n2)]) })
        sig<-lapply(wilcoxResults,function(x) {x<-unlist(x)
                                        p<-unname(x[2])
                                        return(as.numeric(p)) })
        #add row numbers to find consecutive windows
        df1$number<-1:nrow(df1)
        df2$number<-1:nrow(df2)
        #calculate SD for plotting
        df1$sd<-apply(df1[,c(4:(n1+3))], 1, sd)
        df2$sd<-apply(df2[,c(4:(n2+3))], 1, sd)
        
        test<-df1[,c("number","V1","V2","V3")]    
        test$p.value<-unlist(sig)
        test<-test[test$p.value<=0.01,]
        re1<-merge(test, df1[,c("number","V1","V2","V3","mean","sd")])
        re2<-merge(test, df2[,c("number","V1","V2","V3","mean","sd")])
        re1$pop<-pop1
        re2$pop<-pop2
        results<-rbind(re1,re2)
        
        # Find consecutive windows
        re1<-re1[order(re1$number),]
        breaks<-c(0, which(diff(re1$number) != 1),length(re1$number))
        runpos<-sapply(seq(length(breaks)-1),
               function(x) re1$number[(breaks[x]+1):breaks[x+1]])
        runpos3<-Filter(function(x) any(length(unlist(x))>=5), runpos)
        
        # filter the results to only consecutive positions
        if(length(runpos3)>0){
            positions<-unlist(runpos3)
            results<-results[results$number %in% positions,]
            results$comp<-paste0(pop1,"_",pop2)
            Results<-rbind(Results, results)
        }
       }
    write.csv(Results, paste0("../Output/CNV/pairComp/Y2017/runOver5k.Y17.chr",c,".csv"))

    
    ovlap<-as.data.frame.matrix(table(Results$number, Results$comp))
    ovlap<-ovlap/2
    ovlap$sum<-rowSums(ovlap)
    ovlap<-ovlap[ovlap$sum>=2,]
    ovlap$number<-as.integer(rownames(ovlap))
    
    ovlap<-merge(ovlap, re1[,c("number","V2")], by="number")
    write.csv(ovlap,paste0("../Output/CNV/pairComp/Y2017/Overlapping.positions.Y17.runOver5k.chr",c,".csv"))
    
    plots[[c]]<-ggplot(ovlap, aes(x=V2, y=sum))+
        geom_point(size=0.6, color="steelblue")+
        ggtitle(paste0("Chr",c))+
        xlab("")+ylab("No. of population pairs")+
        scale_y_continuous(breaks = seq(2, max(ovlap$sum), by = 1))+
            theme_light()+
        scale_x_continuous(breaks=seq(0, max(re1$V2), by=5000000), labels=comma)+
        theme(panel.grid.minor.y=element_blank())
}


 {pdf(paste0("../Output/CNV/pairComp/Y2017/overlapping_windows_Y2017.pdf"), width = 12, height = 30)
        do.call(grid.arrange, c(plots, ncol=1))
        dev.off()}
# Year2017 populations
y17<-c("TB17","PWS17","SS17","BC17","WA17","CA17")
comb2<-t(combn(y17,2))

#look at some regions from PWS overlaps (especially chr9 with a high coverage region)
#create a slurm script file to extract regions to visualize

sink("../Data/Slurmscripts/Extract_Depth_Y17.sh")
cat("#!/bin/bash -l")
cat("\n")
cat(paste0("#SBATCH --job-name=DepthY17 \n"))
cat(paste0("#SBATCH --mem=16G \n")) 
cat(paste0("#SBATCH --ntasks=1 \n")) 
cat(paste0("#SBATCH -e Extract_Depth1.err  \n"))
cat(paste0("#SBATCH --time=144:00:00  \n"))
cat(paste0("#SBATCH --mail-user=ktist@ucdavis.edu ##email you when job starts,ends,etc \n"))
cat(paste0("#SBATCH --mail-type=ALL \n"))
cat(paste0("#SBATCH -p high  \n"))
cat("\n\n")
cat("module load samtools \n") 

for (j in 1: length(y17)){
    pop<-y17[j]
    samples<-pops_info$Sample[pops_info$Population.Year==pop]
    for (i in 1:40){
        cat(paste0("samtools depth -b /home/ktist/ph/data/bam_depth/Overlaps_reads.bed /home/ktist/ph/data/bam/", samples[i],"_sorted.bam > /home/ktist/ph/data/bam_depth/Y17/",samples[i],"_overlaps.txt \n"))
    cat(paste0("gzip /home/ktist/ph/data/bam_depth/Y17/",samples[i],"_overlaps.txt \n"))
    }
}
sink(NULL)



#nobuffer<-read.table("../Output/CNV/pairComp/PWS_4overlap_regions_noBuffer.bed", sep="\t")
bed<-read.table("../Data/Slurmscripts/Overlaps_reads.bed", sep="\t")

totalreads<-read.csv("../Output/CNV/rawReadTotalCount_perSample.csv")
min(totalreads$rawTotal)
meanTotal<-aggregate(totalreads$rawTotal, by=list(totalreads$pop), mean)
for (j in 1:length(y17)){
    plist<-pops_info$Sample[pops_info$Population.Year==y17[j]]
    depthlist<-list()
    for (i in 1:10){
        df<-fread(paste0("../Data/bam_depth/PWS_overlap/Y17/",plist[i],"_overlaps.txt.gz"))
        total<-totalreads$rawTotal[totalreads$sample==plist[i]]
        df$V3<-df$V3/total*10000000
        reads<-list()
        for (b in 1: nrow(bed)){
            dp<-df[V1==bed$V1[b]& V2>=bed$V2[b] & V2<= bed$V3[b]]
            
            dp$sample<-plist[i]
            reads[[b]]<-dp
        }
        depthlist[[i]]<-reads
        names(depthlist)[i]<-plist[i]
    }
    #saveRDS(depth_list,file=paste0("../Output/CNV/pairComp/PWS_overlap_individual_depth/", pwslist[j],"_depths.RData"))
    
    #for (b in 2: nrow(bed)){
    for (b in 7:7)
        data<-lapply(depthlist, '[[', b)
        depths<-do.call(rbind,data)
        #ymax<-ifelse(b==7|b==6, 60, 30)
        ggplot(depths, aes(x=V2, y=V3))+
            facet_wrap(~sample, ncol=4)+
            geom_point(size=0.3, alpha=0.4, color="#0096FF")+
            ylab("Read depth")+xlab("")+theme_bw()+
            theme(panel.grid = element_blank())+ylim(0,70)+
            ggtitle(paste0(bed$V1[b]," ",bed$V2[b],"-",bed$V3[b]))
            #geom_vline(xintercept = nobuffer$V2[b], color="gray70", size=0.3)+
            #geom_vline(xintercept = nobuffer$V3[b], color="gray70", size=0.3)
        ggsave(paste0("../Output/CNV/pairComp/PWS_overlap_individual_depth/Y17_region",b,".norm10.",y17[j],".png"), width = 12, height=7, dpi=300)
        }
    }
    
        
}


for (c in 1:26){
    df1<-read.csv(paste0("../Output/CNV/pairComp/Y2017/runOver5k.Y17.chr",c,".csv"))
    ov<-read.csv(paste0("../Output/CNV/pairComp/Y2017/Overlapping.positions.Y17.runOver5k.chr",c,".csv"))
    df<-df1[df1$number %in% ov$number,]
    ggplot(df, aes(x=V2, y=mean, color=pop))+
        geom_point(size=0.6, position=position_dodge(width = 100000), alpha=0.5)+
        geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd),position=position_dodge(width = 100000), width=10, size=0.2)+
        ggtitle(paste0("Chr ",c))+
        xlab("")+ylab("normalized mean read count per 1k window")+
        theme(legend.title = element_blank())+xlim(0,chsize$V3[c])+
        theme_bw()
    ggsave(paste0("../Output/CNV/pairComp/Y2017/Overlapping_sites_chr",c,".png"), width = 13, height=3, dpi=300)
}

for (i in 1:nrow(comb2)){
    pop1<-comb2[i,1]
    pop2<-comb2[i,2]
    n1<-nrow(pops_info[pops_info$Population.Year==pop1,])
    n2<-nrow(pops_info[pops_info$Population.Year==pop2,])
    for (c in 1:26){
        df1<-read.csv(paste0("../Output/CNV/ReadNumber_normalized_",pop1, "_chr",c,".csv"))
        df2<-read.csv(paste0("../Output/CNV/ReadNumber_normalized_",pop2, "_chr",c,".csv"))
        combdf<-cbind(df1[,4:(ncol(df1)-1)],df2[,4:(ncol(df2)-1)])
        wilcoxResults<-apply(combdf, 1, function(x){ wilcox.test(x[1:n1],x[(n1+1):(n1+n2)]) })
        sig<-lapply(wilcoxResults,function(x) {x<-unlist(x)
                                        p<-unname(x[2])
                                        return(as.numeric(p)) })
        #add row numbers to find consecutive windows
        df1$number<-1:nrow(df1)
        df2$number<-1:nrow(df2)
        #calculate SD for plotting
        df1$sd<-apply(df1[,c(4:(n1+3))], 1, sd)
        df2$sd<-apply(df2[,c(4:(n2+3))], 1, sd)
        
        test<-df1[,c("number","V1","V2","V3")]    
        test$p.value<-unlist(sig)
        test<-test[test$p.value<=0.01,]
        re1<-merge(test, df1[,c("number","V1","V2","V3","mean","sd")])
        re2<-merge(test, df2[,c("number","V1","V2","V3","mean","sd")])
        re1$pop<-pop1
        re2$pop<-pop2
        results<-rbind(re1,re2)
        
        # Find consecutive windows
        re1<-re1[order(re1$number),]
        breaks<-c(0, which(diff(re1$number) != 1),length(re1$number))
        runpos<-sapply(seq(length(breaks)-1),
               function(x) re1$number[(breaks[x]+1):breaks[x+1]])
        runpos3<-Filter(function(x) any(length(unlist(x))>=3), runpos)
        saveRDS(runpos3,file=paste0("../Output/CNV/pairComp/chr",c,"_",pop1,".",pop2,"_consecutiveWindows.RData"))
        # filter the results to only consective positions
        positions<-unlist(runpos3)
        results<-results[results$number %in% positions,]
        
        plots<-list()
        plots[[1]]<-ggplot(results[results$V3<=10000000,], aes(x=V2, y=mean, color=pop))+
            geom_point(size=0.6, position=position_dodge(width = 0.6))+
            geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd),position=position_dodge(width = 0.6), width=0.3, size=0.2)+
            ggtitle(paste0("Chr",c))+
            xlab("")+ylab("normalized mean read count per 1k")+
            theme(legend.title = element_blank())+
            theme_bw()
        plots[[2]]<-ggplot(results[results$V3<=20000000&results$V3>10000000,], aes(x=V2, y=mean, color=pop))+
            geom_point(size=0.6, position=position_dodge(width = 0.5))+
            geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd),position=position_dodge(width = 0.5), width=0.2, size=0.2)+
            ggtitle(paste0("Chr",c))+
            xlab("")+ylab("normalized mean read count per 1k")+
            theme(legend.title = element_blank())+
            theme_bw()
        plots[[3]]<-ggplot(results[results$V3>20000000,], aes(x=V2, y=mean, color=pop))+
            geom_point(size=0.6, position=position_dodge(width = 0.5))+
            geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd),position=position_dodge(width = 0.5), width=0.2, size=0.2)+
            ggtitle(paste0("Chr",c))+
            xlab("")+ylab("normalized mean read count per 1k")+
            theme(legend.title = element_blank())+
            theme_bw()
     
        {pdf(paste0("../Output/CNV/pairComp/Y17/",pop1,".",pop2,"_chr",c,".pdf"), width = 12, height = 12)
        do.call(grid.arrange, c(plots, ncol=1))
        dev.off()}
        
        
    }
}
#plotting 

for (i in 1:nrow(comb)){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    n1<-ncol(df1)-4
    n2<-ncol(df2)-4
    for (c in 1:26){
        df1<-read.csv(paste0("../Output/CNV/ReadNumber_normalized_",pop1, "_chr",c,".csv"))
        df2<-read.csv(paste0("../Output/CNV/ReadNumber_normalized_",pop2, "_chr",c,".csv"))
        combdf<-cbind(df1[,4:(ncol(df1)-1)],df2[,4:(ncol(df2)-1)])
        wilcoxResults<-apply(combdf, 1, function(x){ wilcox.test(x[1:n1],x[(n1+1):(n1+n2)]) })
        sig<-lapply(wilcoxResults,function(x) {x<-unlist(x)
                                        p<-unname(x[2])
                                        return(as.numeric(p)) })
        
        df1$number<-1:nrow(df1)
        df2$number<-1:nrow(df2)
        test<-df1[,c("number","V1","V2","V3")]    
        test$p.value<-unlist(sig)
        test<-test[test$p.value<=0.01,]
        df1$sd<-apply(df1[,c(4:(ncol(df1)-1))], 1, sd)
        df2$sd<-apply(df2[,c(4:(ncol(df2)-1))], 1, sd)
        re1<-merge(test, df1[,c("number","V1","V2","V3","mean","sd")])
        re2<-merge(test, df2[,c("number","V1","V2","V3","mean","sd")])
        re1$pop<-pop1
        re2$pop<-pop2
        results<-rbind(re1,re2)
        
          
        plots<-list()
        plots[[1]]<-ggplot(results[results$V3<=10000000,], aes(x=V2, y=mean, color=pop))+
            geom_point(size=0.6, position=position_dodge(width = 0.5))+
            geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd),position=position_dodge(width = 0.5), width=0.2, size=0.2)+
            ggtitle(paste0("Chr",c))+
            xlab("")+ylab("normalized mean read count per 1k")+
            theme(legend.title = element_blank())+
            theme_bw()
        plots[[2]]<-ggplot(results[results$V3<=20000000&results$V3>10000000,], aes(x=V2, y=mean, color=pop))+
            geom_point(size=0.6, position=position_dodge(width = 0.5))+
            geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd),position=position_dodge(width = 0.5), width=0.2, size=0.2)+
            ggtitle(paste0("Chr",c))+
            xlab("")+ylab("normalized mean read count per 1k")+
            theme(legend.title = element_blank())+
            theme_bw()+ylab(0,)
        plots[[3]]<-ggplot(results[results$V3>20000000,], aes(x=V2, y=mean, color=pop))+
            geom_point(size=0.6, position=position_dodge(width = 0.5))+
            geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd),position=position_dodge(width = 0.5), width=0.2, size=0.2)+
            ggtitle(paste0("Chr",c))+
            xlab("")+ylab("normalized mean read count per 1k")+
            theme(legend.title = element_blank())+
            theme_bw()
     
        {pdf(paste0("../Output/CNV/pairComp/",pop1,".",pop2,"_chr",c,".pdf"), width = 12, height = 12)
        do.call(grid.arrange, c(plots, ncol=1))
        dev.off()}
        
    }
}
LS0tCnRpdGxlOiAiQXNzZXNzIE1hcHBlZCBSZWFkcyB3aXRoIEJlZHRvb2xzIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgICAgdG9jOiB0cnVlIAogICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgbnVtYmVyX3NlY3Rpb25zOiBUcnVlCiAgICAgIHRoZW1lOiBsdW1lbgogICAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgICBkZl9wcmludDogcGFnZWQKLS0tCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KHNjYWxlcykKc291cmNlKCIuLi9Sc2NyaXB0cy9CYXNlU2NyaXB0cy5SIikKbGlicmFyeShkYXRhLnRhYmxlKQpgYGAKCgoKIyBVc2luZyBiZWR0b29scyB0byBleHRyYWN0IHRoZSBudW1iZXIgb2YgbWFwcGVkIHJlYXMgcGVyIDFrLXdpbmRvdyBwZXIgcG9wdWxhdGlvbgoKIyMgQ3JlYXRlIGJlZCBmaWxlcyB3aXRoIDFrIHdpbmRvd3MgIAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KY2hzaXplPC1yZWFkLnRhYmxlKCIuLi9EYXRhL25ld192Y2YvY2hyX3NpemVzLmJlZCIpCgojUHJldmVudCBzY2llbnRpZmljIG5vdGF0aW9uIGluIGJlZCBmaWxlcwpvcHRpb25zKHNjaXBlbj05OTkpCmxpYnJhcnkoRGF0YUNvbWJpbmUpCgpmb3IgKGkgaW4gMToyNil7CiAgICBsPC1jaHNpemUkVjNbaV0KICAgIGVuZHM8LXNlcSgxMDAwLGwsIGJ5PTEwMDApCiAgICBzdGFydDwtc2VxKDEsbCwgYnk9MTAwMCkgCiAgIAogICAgbmV3PC1kYXRhLmZyYW1lKGNoPXBhc3RlMCgiY2hyIixpKSwgc3Q9c3RhcnQsZW49YyhlbmRzLCBsKSkKICAgIG5ldzwtSW5zZXJ0Um93KG5ldyxjKCJ0cmFjaz1lPWJlZEdyYXBwaCIsICcnLCAnJyksIDEpCiAgICB3cml0ZS50YWJsZShuZXcsIHBhc3RlMCgiLi4vRGF0YS9iYW1fZGVwdGgvYmVkMWsvY2hyIixpLCJfMWsuYmVkIiksIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYsIHF1b3RlID0gRiwgc2VwID0gIlx0IikKfQoKCgpgYGAKCiMjIENyZWF0IGJhc2ggc2NyaXB0cyB0byBzb3J0IGFuZCBpbmRleCBiYW0gZmlsZXMgIAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcG9wc19pbmZvPC1yZWFkLmNzdigiLi4vRGF0YS9TYW1wbGVfbWV0YWRhdGFfODkycG9wcy5jc3YiKQpwb3BzPC11bmlxdWUocG9wc19pbmZvJFBvcHVsYXRpb24uWWVhcikKCgpmb3IgKGkgaW4gMTogbGVuZ3RoKHBvcHMpKXsKICAgIGRmPC1wb3BzX2luZm9bcG9wc19pbmZvJFBvcHVsYXRpb24uWWVhcj09cG9wc1tpXSxdCiAgICBzaW5rKHBhc3RlMCgiLi4vRGF0YS9TbHVybXNjcmlwdHMvc29ydF9iYW1fIiwgcG9wc1tpXSwiLnNoIikpCiAgICBjYXQoIiMhL2Jpbi9iYXNoIC1sXG4iKQogICAgY2F0KHBhc3RlMCgiI1NCQVRDSCAtLWpvYi1uYW1lPXNvcnQiLHBvcHNbaV0sIiBcbiIpKQogICAgY2F0KHBhc3RlMCgiI1NCQVRDSCAtLW1lbT0xNkcgXG4iKSkgCiAgICBjYXQocGFzdGUwKCIjU0JBVENIIC0tbnRhc2tzPTggXG4iKSkgCiAgICBjYXQocGFzdGUwKCIjU0JBVENIIC1lID1zb3J0Iixwb3BzW2ldLCIuZXJyICBcbiIpKQogICAgY2F0KHBhc3RlMCgiI1NCQVRDSCAtLXRpbWU9MjAwOjAwOjAwICBcbiIpKQogICAgY2F0KHBhc3RlMCgiI1NCQVRDSCAtcCBoaWdoICBcbiIpKQogICAgY2F0KCJcblxuIikKICAgIGNhdCgibW9kdWxlIGxvYWQgc2FtdG9vbHMgXG5cbiIpIAogICAgICAgICAKICAgIGZvciAoaiBpbiAxOm5yb3coZGYpKXsKICAgICAgICBjYXQocGFzdGUwKCJzYW10b29scyBzb3J0IC9ob21lL2VvemlvbG9yL3BocG9wZy9kYXRhL2FsaWduLyIsZGYkU2FtcGxlW2pdLCIuYmFtIC1vIC9ob21lL2t0aXN0L3BoL2RhdGEvYmFtLyIsZGYkU2FtcGxlW2pdLCJfc29ydGVkLmJhbSBcbiIpKQogICAgICAgIGNhdChwYXN0ZTAoInNhbXRvb2xzIGluZGV4IC9ob21lL2t0aXN0L3BoL2RhdGEvYmFtLyIsZGYkU2FtcGxlW2pdLCJfc29ydGVkLmJhbSBcbiIpKQogICAgfQogICAgc2luayhOVUxMKQp9CgoKZm9yIChpIGluIDE6IGxlbmd0aChwb3BzKSl7CiAgICBkZjwtcG9wc19pbmZvW3BvcHNfaW5mbyRQb3B1bGF0aW9uLlllYXI9PXBvcHNbaV0sXQogICAgc2luayhwYXN0ZTAoIi4uL0RhdGEvU2x1cm1zY3JpcHRzL2JlZHRvb2xzX2NvdW50XyIsIHBvcHNbaV0sIi5zaCIpKQogICAgY2F0KCIjIS9iaW4vYmFzaCAtbFxuIikKICAgIGNhdChwYXN0ZTAoIiNTQkFUQ0ggLS1qb2ItbmFtZT1jdCIscG9wc1tpXSwiIFxuIikpCiAgICBjYXQocGFzdGUwKCIjU0JBVENIIC0tbWVtPTE2RyBcbiIpKSAKICAgIGNhdChwYXN0ZTAoIiNTQkFUQ0ggLS1udGFza3M9OCBcbiIpKSAKICAgIGNhdChwYXN0ZTAoIiNTQkFUQ0ggLWUgPWN0Iixwb3BzW2ldLCIuZXJyICBcbiIpKQogICAgY2F0KHBhc3RlMCgiI1NCQVRDSCAtLXRpbWU9MjQwOjAwOjAwICBcbiIpKQogICAgY2F0KHBhc3RlMCgiI1NCQVRDSCAtcCBoaWdoICBcbiIpKQogICAgY2F0KCJcblxuIikKICAgIGNhdCgibW9kdWxlIGxvYWQgYmVkdG9vbHMgXG5cbiIpIAogICAgCiAgICBmb3IgKGMgaW4gMToyNil7CiAgICAgICAgY2F0KHBhc3RlMCgiYmVkdG9vbHMgbXVsdGljb3YgLWJhbXMgIikpCiAgICAgICAgZm9yIChqIGluIDE6IG5yb3coZGYpKXsKICAgICAgICAgICAgY2F0KHBhc3RlMCgiL2hvbWUva3Rpc3QvcGgvZGF0YS9iYW0vIixkZiRTYW1wbGVbal0gLCAiX3NvcnRlZC5iYW0gIikpCiAgICAgICAgfQogICAgICAgIGNhdChwYXN0ZTAoIi1iZWQgL2hvbWUva3Rpc3QvcGgvZGF0YS9iYW1fZGVwdGgvY2hyIixjLCJfMWsuYmVkID4gL2hvbWUva3Rpc3QvcGgvZGF0YS9jb3ZlcmFnZS8iLHBvcHNbaV0sIl9jaHIiLGMsIi50eHQgXG4iKSkKICAgIH0KICAgIHNpbmsoTlVMTCkKCn0KCmBgYAoKCiMjIENhbGN1bGF0ZWQgdGhlIG5vcm1hbGl6ZWQgbnVtYmVyIG9mIG1hcHBlZCByZWFkcyAoYmFzZWQgb24gdGhlIHRvdGFsIGNvdW50IG9mIHJlYWRzKQoKKiBMb2NhdGVkIGluIERhdGEvYmFtX2RlcHRoL1JlYWROdW1iZXJzLyAKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBvcHNfaW5mbzwtcmVhZC5jc3YoIi4uL0RhdGEvU2FtcGxlX21ldGFkYXRhXzg5MnBvcHMuY3N2IikKcG9wczwtdW5pcXVlKHBvcHNfaW5mbyRQb3B1bGF0aW9uLlllYXIpCgojIyBHZXQgdGhlIHRvdGFsIHJhdyByZWFkIGNvdW50IHBlciBzYW1wbGUgZnJvbSBlYWNoIGJhbSBmaWxlCnNpbmsoIi4uL0RhdGEvU2x1cm1zY3JpcHRzL1Jhd190b3RhbF9yZWFkX2NvdW50LnNoIikKY2F0KCIjIS9iaW4vYmFzaCAtbFxuIikKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLWpvYi1uYW1lPXRvdGFsUmVhZCBcbiIpKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tbWVtPTE2RyBcbiIpKSAKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLW50YXNrcz04IFxuIikpIApjYXQocGFzdGUwKCIjU0JBVENIIC1lID10b3RhbFJlYWQuZXJyICBcbiIpKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tdGltZT0yNDA6MDA6MDAgIFxuIikpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLXAgaGlnaCAgXG4iKSkKY2F0KCJcblxuIikKY2F0KCJtb2R1bGUgbG9hZCBzYW10b29scyBcblxuIikgCgpmb3IgKGogaW4gMTpucm93KHBvcHNfaW5mbykpewogICAgY2F0KHBhc3RlMCgic2FtdG9vbHMgdmlldyAtYyAtRiAyNjAgIiwgIi9ob21lL2t0aXN0L3BoL2RhdGEvYmFtLyIsIHBvcHNfaW5mbyRTYW1wbGVbal0sICJfc29ydGVkLmJhbSA+ICIsIHBvcHNfaW5mbyRTYW1wbGVbal0sIl9jb3VudC50eHQgXG4iKSkKICAgIH0Kc2luayhOVUxMKQoKCiMgQ29tcGlsZSB0aGUgZmlsZXMgaW50byBvbmUKcmZpbGVzPC1saXN0LmZpbGVzKCIuLi9EYXRhL2JhbV9kZXB0aC9SYXdUb3RhbC8iKQpyYXdUb3RhbDwtZGF0YS5mcmFtZShzYW1wbGU9cmZpbGVzKQpmb3IgKGkgaW4gMTogbGVuZ3RoKHJmaWxlcykpewogICAgZGY8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL2JhbV9kZXB0aC9SYXdUb3RhbC8iLHJmaWxlc1tpXSkpCiAgICBmbmFtZTwtZ3N1YigiX2NvdW50LnR4dCIsICcnLHJmaWxlc1tpXSkKICAgIHJhd1RvdGFsJHNhbXBsZVtpXTwtZm5hbWUKICAgIHJhd1RvdGFsJHBvcFtpXTwtcG9wc19pbmZvJFBvcHVsYXRpb24uWWVhcltwb3BzX2luZm8kU2FtcGxlPT1mbmFtZV0KICAgIHJhd1RvdGFsJHJhd1RvdGFsW2ldPC1kZiRWMVsxXQp9CndyaXRlLmNzdihyYXdUb3RhbCwgIi4uL091dHB1dC9DTlYvcmF3UmVhZFRvdGFsQ291bnRfcGVyU2FtcGxlLmNzdiIsIHJvdy5uYW1lcyA9IEYpCgpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgcG9wPC1wb3BzW2ldCiAgICBwb3BkZjwtcG9wc19pbmZvW3BvcHNfaW5mbyRQb3B1bGF0aW9uLlllYXI9PXBvcCxdCiAgICBuPC1ucm93KHBvcGRmKQogICAgZm9yKGogaW4gMToyNil7CiAgICAgICAgI3JlYWQgdGhlIG1hcHBlZCByZWFkIG51bWJlciBmaWxlCiAgICAgICAgZGY8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL2JhbV9kZXB0aC9SZWFkTnVtYmVycy8iLHBvcCwiX2NociIsaiwiLnR4dCIpKQogICAgICAgICMgbm9ybWFsaXplZCBieSB0aGUgdG90YWwgcmVhZCBjb3VudCAKICAgICAgICBkZjI8LWRmWyw0Om5jb2woZGYpXS9yYXdUb3RhbCRyYXdUb3RhbFtyYXdUb3RhbCRwb3A9PXBvcF0qMTBeNwogICAgICAgICMgY2FsY3VsYXRlIGF2ZXJhZ2UKICAgICAgICBkZjIkbWVhbjwtcm93TWVhbnMoZGYyKQogICAgICAgIHJlYWRzPC1jYmluZChkZlssMTozXSxkZjIpCiAgICAgICAgd3JpdGUuY3N2KHJlYWRzLCBwYXN0ZTAoIi4uL091dHB1dC9DTlYvUmVhZE51bWJlcl9ub3JtYWxpemVkXyIscG9wLCJfY2hyIixqLCcuY3N2JyksIHJvdy5uYW1lcyA9IEYpCiAgICB9Cn0KCgojIGNyZWF0ZSBhIHN1bW1hcnkgb2YgdG90YWwgcmVhZCBjb3VudCBmaWxlIGZvciByZWNvcmQKZm9yIChjIGluIDE6MjYpewogICAgdG90YWw8LWRhdGEuZnJhbWUoKQogICAgZm9yIChpIGluIDE6IGxlbmd0aChwb3BzKSl7CiAgICAgICAgcG9wPC1wb3BzW2ldCiAgICAgICAgcG9wZGY8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L0NOVi9SZWFkTnVtYmVyX25vcm1hbGl6ZWRfIixwb3AsICJfY2hyIixjLCIuY3N2IikpCiAgICAgICAgcG9wZGY8LXBvcGRmWyxjKDE6MywgbmNvbChwb3BkZikpXQogICAgICAgIHBvcGRmJHBvcDwtcG9wCiAgICAgICAgdG90YWw8LXJiaW5kKHRvdGFsLCBwb3BkZikKICAgIH0KICAgIHdyaXRlLmNzdih0b3RhbCwgcGFzdGUwKCIuLi9PdXRwdXQvQ05WL0NociIsYywiX21lYW5SZWFkQ291bnRfcGVyUG9wLmNzdiIpKQp9CgojIFZpc3VhbGl6ZSB0aGUgb3V0cHV0CiNleC4gY2hyMQojYzE8LXJlYWQuY3N2KCIuLi9PdXRwdXQvQ05WL0NocjFfbWVhblJlYWRDb3VudF9wZXJQb3AuY3N2Iiwgcm93Lm5hbWVzID0gMSkKI2dncGxvdCh0b3RhbFt0b3RhbCRWMzwxMDAwMDAwLF0sIGFlcyh4PVYzLCB5PW1lYW4sIGNvbG9yPXBvcCkpKwojICAgICAgICBnZW9tX3BvaW50KHNpemU9LjUpCiMKCmBgYAoKCiMgQ29tcGFyZSB0aGUgbm9ybWFsaXplZCByZWFkIGNvdW50cyBwZXIgMWsgd2luZG93IGJldHdlZW4gcG9wdWxhdGlvbnMgIAoKIyMgMS4gUFdTIGJldHdlZW4geWVhcnMKCiMjIyBQbG90IHRoZSBvdmVybGFwcGluZyByZWdpb25zIGJldHdlZW4gcG9wdWxhdGlvbiBwYWlycyB0byBsb29rIGZvciBjYW5kaWRhdGUgcmVnaW9ucyAgCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwd3M8LWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IikKY29tYjwtdChjb21ibihwd3MsMikpCgpQbG90czwtbGlzdCgpCmZvciAoYyBpbiAxOjI2KXsKICAgIFJlc3VsdHM8LWRhdGEuZnJhbWUoKQogICAgZm9yIChpIGluIDE6bnJvdyhjb21iKSl7CiAgICAgICAgcG9wMTwtY29tYltpLDFdCiAgICAgICAgcG9wMjwtY29tYltpLDJdCiAgICAgICAgbjE8LW5yb3cocG9wc19pbmZvW3BvcHNfaW5mbyRQb3B1bGF0aW9uLlllYXI9PXBvcDEsXSkKICAgICAgICBuMjwtbnJvdyhwb3BzX2luZm9bcG9wc19pbmZvJFBvcHVsYXRpb24uWWVhcj09cG9wMixdKQogICAgICAgIAogICAgICAgIGRmMTwtcmVhZC5jc3YocGFzdGUwKCIuLi9PdXRwdXQvQ05WL1JlYWROdW1iZXJfbm9ybWFsaXplZF8iLHBvcDEsICJfY2hyIixjLCIuY3N2IikpCiAgICAgICAgZGYyPC1yZWFkLmNzdihwYXN0ZTAoIi4uL091dHB1dC9DTlYvUmVhZE51bWJlcl9ub3JtYWxpemVkXyIscG9wMiwgIl9jaHIiLGMsIi5jc3YiKSkKICAgICAgICBjb21iZGY8LWNiaW5kKGRmMVssNDoobmNvbChkZjEpLTEpXSxkZjJbLDQ6KG5jb2woZGYyKS0xKV0pCiAgICAgICAgd2lsY294UmVzdWx0czwtYXBwbHkoY29tYmRmLCAxLCBmdW5jdGlvbih4KXsgd2lsY294LnRlc3QoeFsxOm4xXSx4WyhuMSsxKToobjErbjIpXSkgfSkKICAgICAgICBzaWc8LWxhcHBseSh3aWxjb3hSZXN1bHRzLGZ1bmN0aW9uKHgpIHt4PC11bmxpc3QoeCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHA8LXVubmFtZSh4WzJdKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuKGFzLm51bWVyaWMocCkpIH0pCiAgICAgICAgI2FkZCByb3cgbnVtYmVycyB0byBmaW5kIGNvbnNlY3V0aXZlIHdpbmRvd3MKICAgICAgICBkZjEkbnVtYmVyPC0xOm5yb3coZGYxKQogICAgICAgIGRmMiRudW1iZXI8LTE6bnJvdyhkZjIpCiAgICAgICAgI2NhbGN1bGF0ZSBTRCBmb3IgcGxvdHRpbmcKICAgICAgICBkZjEkc2Q8LWFwcGx5KGRmMVssYyg0OihuMSszKSldLCAxLCBzZCkKICAgICAgICBkZjIkc2Q8LWFwcGx5KGRmMlssYyg0OihuMiszKSldLCAxLCBzZCkKICAgICAgICAKICAgICAgICB0ZXN0PC1kZjFbLGMoIm51bWJlciIsIlYxIiwiVjIiLCJWMyIpXSAgICAKICAgICAgICB0ZXN0JHAudmFsdWU8LXVubGlzdChzaWcpCiAgICAgICAgdGVzdDwtdGVzdFt0ZXN0JHAudmFsdWU8PTAuMDEsXQogICAgICAgIHJlMTwtbWVyZ2UodGVzdCwgZGYxWyxjKCJudW1iZXIiLCJWMSIsIlYyIiwiVjMiLCJtZWFuIiwic2QiKV0pCiAgICAgICAgcmUyPC1tZXJnZSh0ZXN0LCBkZjJbLGMoIm51bWJlciIsIlYxIiwiVjIiLCJWMyIsIm1lYW4iLCJzZCIpXSkKICAgICAgICByZTEkcG9wPC1wb3AxCiAgICAgICAgcmUyJHBvcDwtcG9wMgogICAgICAgIHJlc3VsdHM8LXJiaW5kKHJlMSxyZTIpCiAgICAgICAgCiAgICAgICAgIyBGaW5kIGNvbnNlY3V0aXZlIHdpbmRvd3MKICAgICAgICByZTE8LXJlMVtvcmRlcihyZTEkbnVtYmVyKSxdCiAgICAgICAgYnJlYWtzPC1jKDAsIHdoaWNoKGRpZmYocmUxJG51bWJlcikgIT0gMSksbGVuZ3RoKHJlMSRudW1iZXIpKQogICAgICAgIHJ1bnBvczwtc2FwcGx5KHNlcShsZW5ndGgoYnJlYWtzKS0xKSwKICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgcmUxJG51bWJlclsoYnJlYWtzW3hdKzEpOmJyZWFrc1t4KzFdXSkKICAgICAgICBydW5wb3MzPC1GaWx0ZXIoZnVuY3Rpb24oeCkgYW55KGxlbmd0aCh1bmxpc3QoeCkpPj01KSwgcnVucG9zKQogICAgICAgIAogICAgICAgICMgZmlsdGVyIHRoZSByZXN1bHRzIHRvIG9ubHkgY29uc2VjdXRpdmUgcG9zaXRpb25zCiAgICAgICAgaWYobGVuZ3RoKHJ1bnBvczMpPjApewogICAgICAgICAgICBwb3NpdGlvbnM8LXVubGlzdChydW5wb3MzKQogICAgICAgICAgICByZXN1bHRzPC1yZXN1bHRzW3Jlc3VsdHMkbnVtYmVyICVpbiUgcG9zaXRpb25zLF0KICAgICAgICAgICAgcmVzdWx0cyRjb21wPC1wYXN0ZTAocG9wMSwiXyIscG9wMikKICAgICAgICAgICAgUmVzdWx0czwtcmJpbmQoUmVzdWx0cywgcmVzdWx0cykKICAgICAgICAgICAgd3JpdGUuY3N2KFJlc3VsdHMsIHBhc3RlMCgiLi4vT3V0cHV0L0NOVi9wYWlyQ29tcC9ydW5PdmVyNWsuaW4uY2hyIixjLCIuY3N2IikpCiAgICAgICAgfQogICAgfQogICAgCiAgICAKICAgIG92bGFwPC1hcy5kYXRhLmZyYW1lLm1hdHJpeCh0YWJsZShSZXN1bHRzJG51bWJlciwgUmVzdWx0cyRjb21wKSkKICAgIG92bGFwPC1vdmxhcC8yCiAgICBvdmxhcCRzdW08LXJvd1N1bXMob3ZsYXApCiAgICBvdmxhcDwtb3ZsYXBbb3ZsYXAkc3VtPj0yLF0KICAgIG92bGFwJG51bWJlcjwtYXMuaW50ZWdlcihyb3duYW1lcyhvdmxhcCkpCiAgICAKICAgIG92bGFwPC1tZXJnZShvdmxhcCwgcmUxWyxjKCJudW1iZXIiLCJWMiIpXSwgYnk9Im51bWJlciIpCiAgICB3cml0ZS5jc3Yob3ZsYXAscGFzdGUwKCIuLi9PdXRwdXQvQ05WL3BhaXJDb21wL092ZXJsYXBwaW5nLnBvc2l0aW9ucy5ydW5PdmVyNWsuY2hyIixjLCIuY3N2IikpCiAgICBwbG90c1tbY11dPC1nZ3Bsb3Qob3ZsYXAsIGFlcyh4PVYyLCB5PXN1bSkpKwogICAgICAgIGdlb21fcG9pbnQoc2l6ZT0wLjYsIGNvbG9yPSJzdGVlbGJsdWUiKSsKICAgICAgICBnZ3RpdGxlKHBhc3RlMCgiQ2hyIixjKSkrCiAgICAgICAgeGxhYigiIikreWxhYigiTm8uIG9mIHBvcHVsYXRpb24gcGFpcnMiKSsKICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIsIG1heChvdmxhcCRzdW0pLCBieSA9IDEpKSsKICAgICAgICAgICAgdGhlbWVfbGlnaHQoKSsKICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLCBtYXgocmUxJFYyKSwgYnk9NTAwMDAwMCksIGxhYmVscz1jb21tYSkrCiAgICAgICAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci55PWVsZW1lbnRfYmxhbmsoKSkKfQoKCiB7cGRmKHBhc3RlMCgiLi4vT3V0cHV0L0NOVi9wYWlyQ29tcC9vdmVybGFwcGluZ193aW5kb3dzX1BXUy5wZGYiKSwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gMzApCiAgICAgICAgZG8uY2FsbChncmlkLmFycmFuZ2UsIGMocGxvdHMsIG5jb2w9MSkpCiAgICAgICAgZGV2Lm9mZigpfQogICAgICAgIApgYGAKIVtdKC4uL091dHB1dC9DTlYvcGFpckNvbXAvb3ZlcmxhcHBpbmdfd2luZG93c19QV1MucG5nKQoKIyMjIFBsb3QgdGhlIHJlZ2lvbnMgd2l0aCBQPDAuMDEgZm9yID41IHdpbmRvd3MgcGVyIHBhaXIgIAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiMgUnVuIFdpbGNveG9uIHRlc3QgYW5kIGV4dHJhY3QgdGhlIHNpdGVzIHdpdGggUDwwLjAxIG92ZXIgNSB3aW5kb3dzICg1aykKIyBDcmVhdGUgYSBwYWlyIHRhYmxlIApwd3M8LWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IikKY29tYjwtdChjb21ibihwd3MsMikpCiNyZW9yZGVyIHRoZSBjb21iCmNvbWI8LWNvbWJbYygxLDQsNiwyLDMsNSksXQoKI2Nocm9tb3Nzb21lIHNpemUKY2hzaXplPC1yZWFkLnRhYmxlKCIuLi9EYXRhL25ld192Y2YvY2hyX3NpemVzLmJlZCIpCgojIG5hbWUgdGhlIGNvbG9ycwpjb2xvcnM8LWNvbHNbYygxLDIsMyw1KV0KbmFtZXMoY29sb3JzKTwtcHdzCgpmb3IgKGMgaW4gMToyNil7CiAgICBwbG90bGlzdDwtbGlzdCgpCiAgICBmb3IgKGkgaW4gMTpucm93KGNvbWIpKXsKICAgICAgICBwb3AxPC1jb21iW2ksMV0KICAgICAgICBwb3AyPC1jb21iW2ksMl0KICAgICAgICBuMTwtbnJvdyhwb3BzX2luZm9bcG9wc19pbmZvJFBvcHVsYXRpb24uWWVhcj09cG9wMSxdKQogICAgICAgIG4yPC1ucm93KHBvcHNfaW5mb1twb3BzX2luZm8kUG9wdWxhdGlvbi5ZZWFyPT1wb3AyLF0pCiAgICAgICAgCiAgICAgICAgZGYxPC1yZWFkLmNzdihwYXN0ZTAoIi4uL091dHB1dC9DTlYvUmVhZE51bWJlcl9ub3JtYWxpemVkXyIscG9wMSwgIl9jaHIiLGMsIi5jc3YiKSkKICAgICAgICBkZjI8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L0NOVi9SZWFkTnVtYmVyX25vcm1hbGl6ZWRfIixwb3AyLCAiX2NociIsYywiLmNzdiIpKQogICAgICAgIGNvbWJkZjwtY2JpbmQoZGYxWyw0OihuY29sKGRmMSktMSldLGRmMlssNDoobmNvbChkZjIpLTEpXSkKICAgICAgICB3aWxjb3hSZXN1bHRzPC1hcHBseShjb21iZGYsIDEsIGZ1bmN0aW9uKHgpeyB3aWxjb3gudGVzdCh4WzE6bjFdLHhbKG4xKzEpOihuMStuMildKSB9KQogICAgICAgIHNpZzwtbGFwcGx5KHdpbGNveFJlc3VsdHMsZnVuY3Rpb24oeCkge3g8LXVubGlzdCh4KQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcDwtdW5uYW1lKHhbMl0pCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4oYXMubnVtZXJpYyhwKSkgfSkKICAgICAgICAjYWRkIHJvdyBudW1iZXJzIHRvIGZpbmQgY29uc2VjdXRpdmUgd2luZG93cwogICAgICAgIGRmMSRudW1iZXI8LTE6bnJvdyhkZjEpCiAgICAgICAgZGYyJG51bWJlcjwtMTpucm93KGRmMikKICAgICAgICAjY2FsY3VsYXRlIFNEIGZvciBwbG90dGluZwogICAgICAgIGRmMSRzZDwtYXBwbHkoZGYxWyxjKDQ6KG4xKzMpKV0sIDEsIHNkKQogICAgICAgIGRmMiRzZDwtYXBwbHkoZGYyWyxjKDQ6KG4yKzMpKV0sIDEsIHNkKQogICAgICAgIAogICAgICAgIHRlc3Q8LWRmMVssYygibnVtYmVyIiwiVjEiLCJWMiIsIlYzIildICAgIAogICAgICAgIHRlc3QkcC52YWx1ZTwtdW5saXN0KHNpZykKICAgICAgICB0ZXN0PC10ZXN0W3Rlc3QkcC52YWx1ZTw9MC4wMSxdCiAgICAgICAgcmUxPC1tZXJnZSh0ZXN0LCBkZjFbLGMoIm51bWJlciIsIlYxIiwiVjIiLCJWMyIsIm1lYW4iLCJzZCIpXSkKICAgICAgICByZTI8LW1lcmdlKHRlc3QsIGRmMlssYygibnVtYmVyIiwiVjEiLCJWMiIsIlYzIiwibWVhbiIsInNkIildKQogICAgICAgIHJlMSRwb3A8LXBvcDEKICAgICAgICByZTIkcG9wPC1wb3AyCiAgICAgICAgcmVzdWx0czwtcmJpbmQocmUxLHJlMikKICAgICAgICAKICAgICAgICAjIEZpbmQgY29uc2VjdXRpdmUgd2luZG93cwogICAgICAgIHJlMTwtcmUxW29yZGVyKHJlMSRudW1iZXIpLF0KICAgICAgICBicmVha3M8LWMoMCwgd2hpY2goZGlmZihyZTEkbnVtYmVyKSAhPSAxKSxsZW5ndGgocmUxJG51bWJlcikpCiAgICAgICAgcnVucG9zPC1zYXBwbHkoc2VxKGxlbmd0aChicmVha3MpLTEpLAogICAgICAgICAgICAgICBmdW5jdGlvbih4KSByZTEkbnVtYmVyWyhicmVha3NbeF0rMSk6YnJlYWtzW3grMV1dKQogICAgICAgIHJ1bnBvczM8LUZpbHRlcihmdW5jdGlvbih4KSBhbnkobGVuZ3RoKHVubGlzdCh4KSk+PTUpLCBydW5wb3MpCiAgICAgICAgI3NhdmVSRFMocnVucG9zMyxmaWxlPXBhc3RlMCgiLi4vT3V0cHV0L0NOVi9wYWlyQ29tcC9jaHIiLGMsIl8iLHBvcDEsIi4iLHBvcDIsIl9jb25zZWN1dGl2ZVdpbmRvd3MuUkRhdGEiKSkKICAgICAgICAjIGZpbHRlciB0aGUgcmVzdWx0cyB0byBvbmx5IGNvbnNlY3RpdmUgcG9zaXRpb25zCiAgICAgICAgcG9zaXRpb25zPC11bmxpc3QocnVucG9zMykKICAgICAgICByZXN1bHRzPC1yZXN1bHRzW3Jlc3VsdHMkbnVtYmVyICVpbiUgcG9zaXRpb25zLF0KICAgICAgICAKICAgICAgICBjb2xwYWlyczwtY29sb3JzW2MocG9wMSxwb3AyKV0KICAgICAgICByZXN1bHRzJHBvcDwtZmFjdG9yKHJlc3VsdHMkcG9wLCBsZXZlbHM9cHdzKQogICAgICAgIHBsb3RsaXN0W1tpXV08LWdncGxvdChyZXN1bHRzLCBhZXMoeD1WMiwgeT1tZWFuLCBjb2xvcj1wb3ApKSsKICAgICAgICAgICAgZ2VvbV9wb2ludChzaXplPTEsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSkpKwogICAgICAgICAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPW1lYW4tc2QsIHltYXg9bWVhbitzZCkscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAzKSwgd2lkdGg9MC4zLCBzaXplPTAuMikrCiAgICAgICAgICAgIGdndGl0bGUocGFzdGUwKCJDaHIiLGMsIiAiLCBwb3AxLCItIixwb3AyKSkrCiAgICAgICAgICAgIHhsYWIoIiIpK3lsYWIoIm5vcm1hbGl6ZWQgbWVhbiByZWFkIGNvdW50IHBlciAxayIpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpK3hsaW0oMCxjaHNpemUkVjNbY10pKwogICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXBhc3RlMChjb2xwYWlycywgIjY2IikpKwogICAgICAgICAgICB0aGVtZV9idygpCiAgICAgICAgCiAgICAKICAgIH0KICAgIAogICAge3BkZihwYXN0ZTAoIi4uL091dHB1dC9DTlYvcGFpckNvbXAvY2hyIixjLCJfUFdTXzV3aW5kb3dzLnBkZiIpLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxNikKICAgIGRvLmNhbGwoZ3JpZC5hcnJhbmdlLCBjKHBsb3RsaXN0LCBuY29sPTEpKQogICAgZGV2Lm9mZigpfQogICAgCn0KYGBgCiogQ2hyIDEKIVtdKC4uL091dHB1dC9DTlYvcGFpckNvbXAvY2hyMV9QV1NfNXdpbmRvd3MucG5nKQohW10oLi4vT3V0cHV0L0NOVi9wYWlyQ29tcC9jaHIxNV9QV1NfNXdpbmRvd3MucG5nKQoKIyMjIExvb2sgYXQgdGhlIGJhbSBmaWxlcyBmb3IgdGhlIGNhbmRpZGF0ZSBsb2NpCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIFN0YXJ0IHdpdGggd2luZG93cyB3aXRoIHNpZ25pZmljYW50IHJlYWQgbnVtYmVycyBkaWZmZXJlbmNlIGluIG11bHRpcGxlIHBvcHVsYXRpb24gcGFpcnMKI1ByZXZlbnQgc2NpZW50aWZpYyBub3RhdGlvbiBpbiBiZWQgZmlsZXMKb3B0aW9ucyhzY2lwZW49OTk5KQoKbm9idWZmZXI8LWRhdGEuZnJhbWUoY2hyPSJjaHIiLHN0YXJ0PSJzdGFydCIsZW5kPSJlbmQiKQpiZWRmaWxlPC1kYXRhLmZyYW1lKGNocj0iY2hyIixzdGFydD0ic3RhcnQiLGVuZD0iZW5kIikKCmZvciAoaSBpbiAxOjI2KXsKICAgIGRmPC1yZWFkLmNzdihwYXN0ZTAoIi4uL091dHB1dC9DTlYvcGFpckNvbXAvT3ZlcmxhcHBpbmcucG9zaXRpb25zLnJ1bk92ZXI1ay5jaHIiLGksIi5jc3YiKSkKICAgIGRmPC1kZltkZiRzdW0+PTQsXQogICAgCiAgICBpZiAobnJvdyhkZik+MCl7CiAgICAgICAgYnJlYWtzPC1jKDAsIHdoaWNoKGRpZmYoZGYkbnVtYmVyKSAhPSAxKSxsZW5ndGgoZGYkbnVtYmVyKSkKICAgICAgICBydW5wb3M8LXNhcHBseShzZXEobGVuZ3RoKGJyZWFrcyktMSksCiAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIGRmJG51bWJlclsoYnJlYWtzW3hdKzEpOmJyZWFrc1t4KzFdXSkKICAgICAgICAKICAgICAgICBpZiAoaXMubGlzdChydW5wb3MpKSB7CiAgICAgICAgICAgIHJ1bnBvczwtRmlsdGVyKGZ1bmN0aW9uKHgpIGFueShsZW5ndGgodW5saXN0KHgpKT49NSksIHJ1bnBvcykKICAgICAgICAgICAgZm9yIChqIGluIDE6bGVuZ3RoKHJ1bnBvcykpewogICAgICAgICAgICAgICAgcG9zPC1ydW5wb3Nbal0KICAgICAgICAgICAgICAgIHBvczwtdW5saXN0KHBvcykKICAgICAgICAgICAgICAgICNubyBidWZmZXIgYmVkZmlsZQogICAgICAgICAgICAgICAgYmVkMTwtZGF0YS5mcmFtZShjaHI9cGFzdGUwKCJjaHIiLGkpLCBzdGFydD1kZiRWMltkZiRudW1iZXI9PXBvc1sxXV0sIGVuZD1kZiRWMltkZiAgICAkbnVtYmVyPT1wb3NbbGVuZ3RoKHBvcyldXSs5OTkpCiAgICAgICAgICAgICAgICBub2J1ZmZlcjwtcmJpbmQobm9idWZmZXIsIGJlZDEpICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAjIGFkZCA1MGsgYnVmZmVyIGFyb3VuZCB0aGUgYmVkIGZpbGVzCiAgICAgICAgICAgICAgICBiZWQ8LWRhdGEuZnJhbWUoY2hyPXBhc3RlMCgiY2hyIixpKSwgc3RhcnQ9ZGYkVjJbZGYkbnVtYmVyPT1wb3NbMV1dLCBlbmQ9ZGYkVjJbZGYgICAgJG51bWJlcj09cG9zW2xlbmd0aChwb3MpXV0rOTk5KzUwMDAwKQogICAgICAgICAgICAgICAgaWYgKGJlZCRzdGFydFsxXTw1MDAwMCkgYmVkJHN0YXJ0WzFdPC0wCiAgICAgICAgICAgICAgICBpZiAoYmVkJHN0YXJ0WzFdPj01MDAwMCkgYmVkJHN0YXJ0WzFdPC1iZWQkc3RhcnRbMV0tNTAwMDAKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgYmVkZmlsZTwtcmJpbmQoYmVkZmlsZSxiZWQpCiAgICAgICAgICAgIH0KICAgICAgICAKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgaWYgKCFpcy5saXN0KHJ1bnBvcykpewogICAgICAgICAgICBpZiAobnJvdyhydW5wb3MpPj01KXsKICAgICAgICAgICAgICAgIGJlZDwtZGF0YS5mcmFtZShjaHI9cGFzdGUwKCJjaHIiLGkpLCBzdGFydD1ydW5wb3NbMSwxXSwgZW5kPXJ1bnBvc1tucm93KHJ1bnBvcyksMV0rOTk5KzUwMDAwKQogICAgICAgICAgICAgICAgaWYgKGJlZCRzdGFydFsxXTw1MDAwMCkgYmVkJHN0YXJ0WzFdPC0wCiAgICAgICAgICAgICAgICBpZiAoYmVkJHN0YXJ0WzFdPj01MDAwMCkgYmVkJHN0YXJ0WzFdPC1iZWQkc3RhcnRbMV0tNTAwMDAKICAgICAgICAgICAgICAgIGJlZGZpbGU8LXJiaW5kKGJlZGZpbGUsYmVkKQogICAgICAgICAgICAgICAgYmVkMTwtZGF0YS5mcmFtZShjaHI9cGFzdGUwKCJjaHIiLGkpLCBzdGFydD1ydW5wb3NbMSwxXSwgZW5kPXJ1bnBvc1tucm93KHJ1bnBvcyksMV0rOTk5KQogICAgICAgICAgICAgICAgbm9idWZmZXI8LXJiaW5kKG5vYnVmZmVyLCBiZWQxKSAgICAKICAgICAgICAgICAgICAgIAogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgIH0KICAgICAgICAKICAgICAgICAKICAgIH0KfQpiZWRmaWxlPC1iZWRmaWxlWy0xLF0Kd3JpdGUudGFibGUoYmVkZmlsZSwgIi4uL091dHB1dC9DTlYvcGFpckNvbXAvUFdTXzRvdmVybGFwX3JlZ2lvbnMuYmVkIiwgcm93Lm5hbWVzPUYsIGNvbC5uYW1lcz1GLHF1b3RlPUYsIHNlcD0iXHQiKQpub2J1ZmZlcjwtbm9idWZmZXJbLTEsXQp3cml0ZS50YWJsZShub2J1ZmZlciwgIi4uL091dHB1dC9DTlYvcGFpckNvbXAvUFdTXzRvdmVybGFwX3JlZ2lvbnNfbm9CdWZmZXIuYmVkIiwgcm93Lm5hbWVzPUYsIGNvbC5uYW1lcz1GLHF1b3RlPUYsIHNlcD0iXHQiKQogCgogICAKI2NyZWF0ZSBhIHNsdXJtIHNjcmlwdCBmaWxlIHRvIGV4dHJhY3QgcmVnaW9ucyB0byB2aXN1YWxpemUKCnB3czk2PC1wb3BzX2luZm8kU2FtcGxlW3BvcHNfaW5mbyRQb3B1bGF0aW9uLlllYXI9PSJQV1M5NiJdCnB3czkxPC1wb3BzX2luZm8kU2FtcGxlW3BvcHNfaW5mbyRQb3B1bGF0aW9uLlllYXI9PSJQV1M5MSJdCnB3czA3PC1wb3BzX2luZm8kU2FtcGxlW3BvcHNfaW5mbyRQb3B1bGF0aW9uLlllYXI9PSJQV1MwNyJdCnB3czE3PC1wb3BzX2luZm8kU2FtcGxlW3BvcHNfaW5mbyRQb3B1bGF0aW9uLlllYXI9PSJQV1MxNyJdCgpzaW5rKCIuLi9EYXRhL1NsdXJtc2NyaXB0cy9FeHRyYWN0X0RlcHRoX1BXUy5zaCIpCmNhdCgiIyEvYmluL2Jhc2ggLWwiKQpjYXQoIlxuIikKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLWpvYi1uYW1lPURlcHRoUFdTIFxuIikpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLS1tZW09MTZHIFxuIikpIApjYXQocGFzdGUwKCIjU0JBVENIIC0tbnRhc2tzPTEgXG4iKSkgCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLWUgRXh0cmFjdF9EZXB0aDEuZXJyICBcbiIpKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tdGltZT0xNDQ6MDA6MDAgIFxuIikpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLS1tYWlsLXVzZXI9a3Rpc3RAdWNkYXZpcy5lZHUgIyNlbWFpbCB5b3Ugd2hlbiBqb2Igc3RhcnRzLGVuZHMsZXRjIFxuIikpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLS1tYWlsLXR5cGU9QUxMIFxuIikpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLXAgaGlnaCAgXG4iKSkKY2F0KCJcblxuIikKY2F0KCJtb2R1bGUgbG9hZCBzYW10b29scyBcbiIpIAoKZm9yIChpIGluIDE6MjApewogICAgY2F0KHBhc3RlMCgic2FtdG9vbHMgZGVwdGggLWIgL2hvbWUva3Rpc3QvcGgvZGF0YS9iYW1fZGVwdGgvUFdTXzRvdmVybGFwX3JlZ2lvbnMuYmVkIC9ob21lL2t0aXN0L3BoL2RhdGEvYmFtLyIsIHB3czkxW2ldLCJfc29ydGVkLmJhbSA+IC9ob21lL2t0aXN0L3BoL2RhdGEvYmFtX2RlcHRoL1BXUy8iLHB3czkxW2ldLCJfb3ZlcmxhcFJlZ2lvbnMudHh0IFxuIikpCiAgICBjYXQocGFzdGUwKCJnemlwIC9ob21lL2t0aXN0L3BoL2RhdGEvYmFtX2RlcHRoL1BXUy8iLHB3czkxW2ldLCJfb3ZlcmxhcFJlZ2lvbnMudHh0IFxuIikpCiAgICAKICAgIGNhdChwYXN0ZTAoInNhbXRvb2xzIGRlcHRoIC1iIC9ob21lL2t0aXN0L3BoL2RhdGEvYmFtX2RlcHRoL1BXU180b3ZlcmxhcF9yZWdpb25zLmJlZCAvaG9tZS9rdGlzdC9waC9kYXRhL2JhbS8iLCBwd3M5NltpXSwiX3NvcnRlZC5iYW0gPiAvaG9tZS9rdGlzdC9waC9kYXRhL2JhbV9kZXB0aC9QV1MvIixwd3M5NltpXSwiX292ZXJsYXBSZWdpb25zLnR4dCBcbiIpKQogICAgY2F0KHBhc3RlMCgiZ3ppcCAvaG9tZS9rdGlzdC9waC9kYXRhL2JhbV9kZXB0aC9QV1MvIixwd3M5NltpXSwiX292ZXJsYXBSZWdpb25zLnR4dCBcbiIpKQogICAgCiAgICBjYXQocGFzdGUwKCJzYW10b29scyBkZXB0aCAtYiAvaG9tZS9rdGlzdC9waC9kYXRhL2JhbV9kZXB0aC9QV1NfNG92ZXJsYXBfcmVnaW9ucy5iZWQgL2hvbWUva3Rpc3QvcGgvZGF0YS9iYW0vIiwgcHdzMDdbaV0sIl9zb3J0ZWQuYmFtID4gL2hvbWUva3Rpc3QvcGgvZGF0YS9iYW1fZGVwdGgvUFdTLyIscHdzMDdbaV0sIl9vdmVybGFwUmVnaW9ucy50eHQgXG4iKSkKICAgIGNhdChwYXN0ZTAoImd6aXAgL2hvbWUva3Rpc3QvcGgvZGF0YS9iYW1fZGVwdGgvUFdTLyIscHdzMDdbaV0sIl9vdmVybGFwUmVnaW9ucy50eHQgXG4iKSkKICAgICBjYXQocGFzdGUwKCJzYW10b29scyBkZXB0aCAtYiAvaG9tZS9rdGlzdC9waC9kYXRhL2JhbV9kZXB0aC9QV1NfNG92ZXJsYXBfcmVnaW9ucy5iZWQgL2hvbWUva3Rpc3QvcGgvZGF0YS9iYW0vIiwgcHdzMTdbaV0sIl9zb3J0ZWQuYmFtID4gL2hvbWUva3Rpc3QvcGgvZGF0YS9iYW1fZGVwdGgvUFdTLyIscHdzMTdbaV0sIl9vdmVybGFwUmVnaW9ucy50eHQgXG4iKSkKICAgIGNhdChwYXN0ZTAoImd6aXAgL2hvbWUva3Rpc3QvcGgvZGF0YS9iYW1fZGVwdGgvUFdTLyIscHdzMTdbaV0sIl9vdmVybGFwUmVnaW9ucy50eHQgXG4iKSkKfQpzaW5rKE5VTEwpCgojcGxvdCB0aGUgcmVzdWx0cyBwZXIgcmVnaW9ucwoKCnB3c2xpc3Q8LWMoInB3czkxIiwicHdzOTYiLCJwd3MwNyIsInB3czE3IikKCm5vYnVmZmVyPC1yZWFkLnRhYmxlKCIuLi9PdXRwdXQvQ05WL3BhaXJDb21wL1BXU180b3ZlcmxhcF9yZWdpb25zX25vQnVmZmVyLmJlZCIsIHNlcD0iXHQiKQpiZWRmaWxlPC1yZWFkLnRhYmxlKCIuLi9PdXRwdXQvQ05WL3BhaXJDb21wL1BXU180b3ZlcmxhcF9yZWdpb25zLmJlZCIsIHNlcD0iXHQiKQoKdG90YWxyZWFkczwtcmVhZC5jc3YoIi4uL091dHB1dC9DTlYvcmF3UmVhZFRvdGFsQ291bnRfcGVyU2FtcGxlLmNzdiIpCgpmb3IgKGogaW4gMTpsZW5ndGgocHdzbGlzdCkpewogICAgcGxpc3Q8LWdldChwYXN0ZTAocHdzbGlzdFtqXSkpCiAgICBkZXB0aF9saXN0PC1saXN0KCkKICAgIGZvciAoaSBpbiAxOjIwKXsKICAgICAgICBkZjwtZnJlYWQocGFzdGUwKCIuLi9EYXRhL2JhbV9kZXB0aC9QV1Nfb3ZlcmxhcC8iLHBsaXN0W2ldLCJfb3ZlcmxhcFJlZ2lvbnMudHh0Lmd6IikpCiAgICAgICAgCiAgICAgICAgcmVhZHM8LWxpc3QoKQogICAgICAgIGZvciAoYiBpbiAxOiBucm93KGJlZGZpbGUpKXsKICAgICAgICAgICAgZHA8LWRmW1YxPT1iZWRmaWxlJFYxW2JdJiBWMj49YmVkZmlsZSRWMltiXSAmIFYyPD0gYmVkZmlsZSRWM1tiXV0KICAgICAgICAgICAgZHAkc2FtcGxlPC1wbGlzdFtpXQogICAgICAgICAgICByZWFkc1tbYl1dPC1kcAogICAgICAgIH0KICAgICAgICBkZXB0aF9saXN0W1tpXV08LXJlYWRzCiAgICAgICAgbmFtZXMoZGVwdGhfbGlzdClbaV08LXBsaXN0W2ldCiAgICB9CiAgICAjc2F2ZVJEUyhkZXB0aF9saXN0LGZpbGU9cGFzdGUwKCIuLi9PdXRwdXQvQ05WL3BhaXJDb21wL1BXU19vdmVybGFwX2luZGl2aWR1YWxfZGVwdGgvIiwgcHdzbGlzdFtqXSwiX2RlcHRocy5SRGF0YSIpKQogICAgCiAgICBmb3IgKGIgaW4gMTogbnJvdyhiZWRmaWxlKSl7CiAgICAgICAgZGF0YTwtbGFwcGx5KGRlcHRoX2xpc3QsICdbWycsIGIpCiAgICAgICAgZGVwdGhzPC1kby5jYWxsKHJiaW5kLGRhdGEpCiAgICAgICAgZ2dwbG90KGRlcHRocywgYWVzKHg9VjIsIHk9VjMpKSsKICAgICAgICAgICAgZmFjZXRfd3JhcCh+c2FtcGxlLCBuY29sPTQpKwogICAgICAgICAgICBnZW9tX3BvaW50KHNpemU9MC4zLCBhbHBoYT0wLjQsIGNvbG9yPSJibHVlIikrCiAgICAgICAgICAgIHlsYWIoIlJlYWQgZGVwdGgiKSt4bGFiKCIiKSt0aGVtZV9idygpKwogICAgICAgICAgICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpKSt5bGltKDAsMzApKwogICAgICAgICAgICBnZ3RpdGxlKHBhc3RlMChiZWRmaWxlJFYxW2JdLCIgIixub2J1ZmZlciRWMltiXSwiLSIsbm9idWZmZXIkVjNbYl0pKSsKICAgICAgICAgICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbm9idWZmZXIkVjJbYl0sIGNvbG9yPSJncmF5NzAiLCBzaXplPTAuMykrCiAgICAgICAgICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IG5vYnVmZmVyJFYzW2JdLCBjb2xvcj0iZ3JheTcwIiwgc2l6ZT0wLjMpCiAgICAgICAgZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L0NOVi9wYWlyQ29tcC9QV1Nfb3ZlcmxhcF9pbmRpdmlkdWFsX2RlcHRoL3JlZ2lvbl8iLGIsIl8iLHB3c2xpc3Rbal0sIi5wbmciKSwgd2lkdGggPSAxMiwgaGVpZ2h0PTksIGRwaT0zMDApCiAgICAgICAgfQogICAgfQogICAgCiAgICAgICAgCn0KICAgICAgICAKZGVwdGhfbGlzdDwtcmVhZFJEUyhmaWxlPSIuLi9PdXRwdXQvQ05WL3BhaXJDb21wL1BXU19vdmVybGFwX2luZGl2aWR1YWxfZGVwdGgvcHdzOTFfZGVwdGhzLlJEYXRhIikKaj0xCgpmb3IgKGIgaW4gMjogbnJvdyhiZWRmaWxlKSl7CiAgICAgICAgZGF0YTwtbGFwcGx5KGRlcHRoX2xpc3QsICdbWycsIGIpCiAgICAgICAgZGVwdGhzPC1kby5jYWxsKHJiaW5kLGRhdGEpCiAgICAgICAgZ2dwbG90KGRlcHRocywgYWVzKHg9VjIsIHk9VjMpKSsKICAgICAgICAgICAgZmFjZXRfd3JhcCh+c2FtcGxlLCBuY29sPTQpKwogICAgICAgICAgICBnZW9tX3BvaW50KHNpemU9MC4zLCBhbHBoYT0wLjQsIGNvbG9yPSJibHVlIikrCiAgICAgICAgICAgIHlsYWIoIlJlYWQgZGVwdGgiKSt4bGFiKCIiKSt0aGVtZV9idygpKwogICAgICAgICAgICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpKSt5bGltKDAsMzApKwogICAgICAgICAgICBnZ3RpdGxlKHBhc3RlMChiZWRmaWxlJFYxW2JdLCIgIixub2J1ZmZlciRWMltiXSwiLSIsbm9idWZmZXIkVjNbYl0pKSsKICAgICAgICAgICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbm9idWZmZXIkVjJbYl0sIGNvbG9yPSJncmF5NzAiLCBzaXplPTAuMykrCiAgICAgICAgICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IG5vYnVmZmVyJFYzW2JdLCBjb2xvcj0iZ3JheTcwIiwgc2l6ZT0wLjMpCiAgICAgICAgZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L0NOVi9wYWlyQ29tcC9QV1Nfb3ZlcmxhcF9pbmRpdmlkdWFsX2RlcHRoL3JlZ2lvbl8iLGIsIl8iLHB3c2xpc3Rbal0sIi5wbmciKSwgd2lkdGggPSAxMiwgaGVpZ2h0PTksIGRwaT0zMDApCiAgICAgICAgfQoKCmBgYAoKCiMjIDIuIFllYXIgMjAxNyBwb3B1bGF0aW9uIGNvbXBhcmlzb24KCiMjIDEuIFBXUyBiZXR3ZWVuIHllYXJzCgojIyMgUGxvdCB0aGUgb3ZlcmxhcHBpbmcgcmVnaW9ucyBiZXR3ZWVuIHBvcHVsYXRpb24gcGFpcnMgdG8gbG9vayBmb3IgY2FuZGlkYXRlIHJlZ2lvbnMgIAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBZZWFyMjAxNyBwb3B1bGF0aW9ucwp5MTc8LWMoIlRCMTciLCJQV1MxNyIsIlNTMTciLCJCQzE3IiwiV0ExNyIsIkNBMTciKQpjb21iMjwtdChjb21ibih5MTcsMikpCgoKcGxvdHM8LWxpc3QoKQpmb3IgKGMgaW4gMjoyNil7CiAgICBSZXN1bHRzPC1kYXRhLmZyYW1lKCkKICAgIGZvciAoaSBpbiAxOm5yb3coY29tYjIpKXsKICAgICAgICBwb3AxPC1jb21iMltpLDFdCiAgICAgICAgcG9wMjwtY29tYjJbaSwyXQogICAgICAgIG4xPC1ucm93KHBvcHNfaW5mb1twb3BzX2luZm8kUG9wdWxhdGlvbi5ZZWFyPT1wb3AxLF0pCiAgICAgICAgbjI8LW5yb3cocG9wc19pbmZvW3BvcHNfaW5mbyRQb3B1bGF0aW9uLlllYXI9PXBvcDIsXSkKICAgICAgICAKICAgICAgICBkZjE8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L0NOVi9SZWFkTnVtYmVyX25vcm1hbGl6ZWRfIixwb3AxLCAiX2NociIsYywiLmNzdiIpKQogICAgICAgIGRmMjwtcmVhZC5jc3YocGFzdGUwKCIuLi9PdXRwdXQvQ05WL1JlYWROdW1iZXJfbm9ybWFsaXplZF8iLHBvcDIsICJfY2hyIixjLCIuY3N2IikpCiAgICAgICAgY29tYmRmPC1jYmluZChkZjFbLDQ6KG5jb2woZGYxKS0xKV0sZGYyWyw0OihuY29sKGRmMiktMSldKQogICAgICAgIHdpbGNveFJlc3VsdHM8LWFwcGx5KGNvbWJkZiwgMSwgZnVuY3Rpb24oeCl7IHdpbGNveC50ZXN0KHhbMTpuMV0seFsobjErMSk6KG4xK24yKV0pIH0pCiAgICAgICAgc2lnPC1sYXBwbHkod2lsY294UmVzdWx0cyxmdW5jdGlvbih4KSB7eDwtdW5saXN0KHgpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwPC11bm5hbWUoeFsyXSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybihhcy5udW1lcmljKHApKSB9KQogICAgICAgICNhZGQgcm93IG51bWJlcnMgdG8gZmluZCBjb25zZWN1dGl2ZSB3aW5kb3dzCiAgICAgICAgZGYxJG51bWJlcjwtMTpucm93KGRmMSkKICAgICAgICBkZjIkbnVtYmVyPC0xOm5yb3coZGYyKQogICAgICAgICNjYWxjdWxhdGUgU0QgZm9yIHBsb3R0aW5nCiAgICAgICAgZGYxJHNkPC1hcHBseShkZjFbLGMoNDoobjErMykpXSwgMSwgc2QpCiAgICAgICAgZGYyJHNkPC1hcHBseShkZjJbLGMoNDoobjIrMykpXSwgMSwgc2QpCiAgICAgICAgCiAgICAgICAgdGVzdDwtZGYxWyxjKCJudW1iZXIiLCJWMSIsIlYyIiwiVjMiKV0gICAgCiAgICAgICAgdGVzdCRwLnZhbHVlPC11bmxpc3Qoc2lnKQogICAgICAgIHRlc3Q8LXRlc3RbdGVzdCRwLnZhbHVlPD0wLjAxLF0KICAgICAgICByZTE8LW1lcmdlKHRlc3QsIGRmMVssYygibnVtYmVyIiwiVjEiLCJWMiIsIlYzIiwibWVhbiIsInNkIildKQogICAgICAgIHJlMjwtbWVyZ2UodGVzdCwgZGYyWyxjKCJudW1iZXIiLCJWMSIsIlYyIiwiVjMiLCJtZWFuIiwic2QiKV0pCiAgICAgICAgcmUxJHBvcDwtcG9wMQogICAgICAgIHJlMiRwb3A8LXBvcDIKICAgICAgICByZXN1bHRzPC1yYmluZChyZTEscmUyKQogICAgICAgIAogICAgICAgICMgRmluZCBjb25zZWN1dGl2ZSB3aW5kb3dzCiAgICAgICAgcmUxPC1yZTFbb3JkZXIocmUxJG51bWJlciksXQogICAgICAgIGJyZWFrczwtYygwLCB3aGljaChkaWZmKHJlMSRudW1iZXIpICE9IDEpLGxlbmd0aChyZTEkbnVtYmVyKSkKICAgICAgICBydW5wb3M8LXNhcHBseShzZXEobGVuZ3RoKGJyZWFrcyktMSksCiAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHJlMSRudW1iZXJbKGJyZWFrc1t4XSsxKTpicmVha3NbeCsxXV0pCiAgICAgICAgcnVucG9zMzwtRmlsdGVyKGZ1bmN0aW9uKHgpIGFueShsZW5ndGgodW5saXN0KHgpKT49NSksIHJ1bnBvcykKICAgICAgICAKICAgICAgICAjIGZpbHRlciB0aGUgcmVzdWx0cyB0byBvbmx5IGNvbnNlY3V0aXZlIHBvc2l0aW9ucwogICAgICAgIGlmKGxlbmd0aChydW5wb3MzKT4wKXsKICAgICAgICAgICAgcG9zaXRpb25zPC11bmxpc3QocnVucG9zMykKICAgICAgICAgICAgcmVzdWx0czwtcmVzdWx0c1tyZXN1bHRzJG51bWJlciAlaW4lIHBvc2l0aW9ucyxdCiAgICAgICAgICAgIHJlc3VsdHMkY29tcDwtcGFzdGUwKHBvcDEsIl8iLHBvcDIpCiAgICAgICAgICAgIFJlc3VsdHM8LXJiaW5kKFJlc3VsdHMsIHJlc3VsdHMpCiAgICAgICAgfQogICAgICAgfQogICAgd3JpdGUuY3N2KFJlc3VsdHMsIHBhc3RlMCgiLi4vT3V0cHV0L0NOVi9wYWlyQ29tcC9ZMjAxNy9ydW5PdmVyNWsuWTE3LmNociIsYywiLmNzdiIpKQoKICAgIAogICAgb3ZsYXA8LWFzLmRhdGEuZnJhbWUubWF0cml4KHRhYmxlKFJlc3VsdHMkbnVtYmVyLCBSZXN1bHRzJGNvbXApKQogICAgb3ZsYXA8LW92bGFwLzIKICAgIG92bGFwJHN1bTwtcm93U3VtcyhvdmxhcCkKICAgIG92bGFwPC1vdmxhcFtvdmxhcCRzdW0+PTIsXQogICAgb3ZsYXAkbnVtYmVyPC1hcy5pbnRlZ2VyKHJvd25hbWVzKG92bGFwKSkKICAgIAogICAgb3ZsYXA8LW1lcmdlKG92bGFwLCByZTFbLGMoIm51bWJlciIsIlYyIildLCBieT0ibnVtYmVyIikKICAgIHdyaXRlLmNzdihvdmxhcCxwYXN0ZTAoIi4uL091dHB1dC9DTlYvcGFpckNvbXAvWTIwMTcvT3ZlcmxhcHBpbmcucG9zaXRpb25zLlkxNy5ydW5PdmVyNWsuY2hyIixjLCIuY3N2IikpCiAgICAKICAgIHBsb3RzW1tjXV08LWdncGxvdChvdmxhcCwgYWVzKHg9VjIsIHk9c3VtKSkrCiAgICAgICAgZ2VvbV9wb2ludChzaXplPTAuNiwgY29sb3I9InN0ZWVsYmx1ZSIpKwogICAgICAgIGdndGl0bGUocGFzdGUwKCJDaHIiLGMpKSsKICAgICAgICB4bGFiKCIiKSt5bGFiKCJOby4gb2YgcG9wdWxhdGlvbiBwYWlycyIpKwogICAgICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMiwgbWF4KG92bGFwJHN1bSksIGJ5ID0gMSkpKwogICAgICAgICAgICB0aGVtZV9saWdodCgpKwogICAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9c2VxKDAsIG1heChyZTEkVjIpLCBieT01MDAwMDAwKSwgbGFiZWxzPWNvbW1hKSsKICAgICAgICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yLnk9ZWxlbWVudF9ibGFuaygpKQp9CgoKIHtwZGYocGFzdGUwKCIuLi9PdXRwdXQvQ05WL3BhaXJDb21wL1kyMDE3L292ZXJsYXBwaW5nX3dpbmRvd3NfWTIwMTcucGRmIiksIHdpZHRoID0gMTIsIGhlaWdodCA9IDMwKQogICAgICAgIGRvLmNhbGwoZ3JpZC5hcnJhbmdlLCBjKHBsb3RzLCBuY29sPTEpKQogICAgICAgIGRldi5vZmYoKX0KICAgICAgICAKYGBgCgoKCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIFllYXIyMDE3IHBvcHVsYXRpb25zCnkxNzwtYygiVEIxNyIsIlBXUzE3IiwiU1MxNyIsIkJDMTciLCJXQTE3IiwiQ0ExNyIpCmNvbWIyPC10KGNvbWJuKHkxNywyKSkKCiNsb29rIGF0IHNvbWUgcmVnaW9ucyBmcm9tIFBXUyBvdmVybGFwc+OAgChlc3BlY2lhbGx5IGNocjkgd2l0aCBhIGhpZ2ggY292ZXJhZ2UgcmVnaW9uKQojY3JlYXRlIGEgc2x1cm0gc2NyaXB0IGZpbGUgdG8gZXh0cmFjdCByZWdpb25zIHRvIHZpc3VhbGl6ZQoKc2luaygiLi4vRGF0YS9TbHVybXNjcmlwdHMvRXh0cmFjdF9EZXB0aF9ZMTcuc2giKQpjYXQoIiMhL2Jpbi9iYXNoIC1sIikKY2F0KCJcbiIpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLS1qb2ItbmFtZT1EZXB0aFkxNyBcbiIpKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tbWVtPTE2RyBcbiIpKSAKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLW50YXNrcz0xIFxuIikpIApjYXQocGFzdGUwKCIjU0JBVENIIC1lIEV4dHJhY3RfRGVwdGgxLmVyciAgXG4iKSkKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLXRpbWU9MTQ0OjAwOjAwICBcbiIpKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tbWFpbC11c2VyPWt0aXN0QHVjZGF2aXMuZWR1ICMjZW1haWwgeW91IHdoZW4gam9iIHN0YXJ0cyxlbmRzLGV0YyBcbiIpKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tbWFpbC10eXBlPUFMTCBcbiIpKQpjYXQocGFzdGUwKCIjU0JBVENIIC1wIGhpZ2ggIFxuIikpCmNhdCgiXG5cbiIpCmNhdCgibW9kdWxlIGxvYWQgc2FtdG9vbHMgXG4iKSAKCmZvciAoaiBpbiAxOiBsZW5ndGgoeTE3KSl7CiAgICBwb3A8LXkxN1tqXQogICAgc2FtcGxlczwtcG9wc19pbmZvJFNhbXBsZVtwb3BzX2luZm8kUG9wdWxhdGlvbi5ZZWFyPT1wb3BdCiAgICBmb3IgKGkgaW4gMTo0MCl7CiAgICAgICAgY2F0KHBhc3RlMCgic2FtdG9vbHMgZGVwdGggLWIgL2hvbWUva3Rpc3QvcGgvZGF0YS9iYW1fZGVwdGgvT3ZlcmxhcHNfcmVhZHMuYmVkIC9ob21lL2t0aXN0L3BoL2RhdGEvYmFtLyIsIHNhbXBsZXNbaV0sIl9zb3J0ZWQuYmFtID4gL2hvbWUva3Rpc3QvcGgvZGF0YS9iYW1fZGVwdGgvWTE3LyIsc2FtcGxlc1tpXSwiX292ZXJsYXBzLnR4dCBcbiIpKQogICAgY2F0KHBhc3RlMCgiZ3ppcCAvaG9tZS9rdGlzdC9waC9kYXRhL2JhbV9kZXB0aC9ZMTcvIixzYW1wbGVzW2ldLCJfb3ZlcmxhcHMudHh0IFxuIikpCiAgICB9Cn0Kc2luayhOVUxMKQoKCgojbm9idWZmZXI8LXJlYWQudGFibGUoIi4uL091dHB1dC9DTlYvcGFpckNvbXAvUFdTXzRvdmVybGFwX3JlZ2lvbnNfbm9CdWZmZXIuYmVkIiwgc2VwPSJcdCIpCmJlZDwtcmVhZC50YWJsZSgiLi4vRGF0YS9TbHVybXNjcmlwdHMvT3ZlcmxhcHNfcmVhZHMuYmVkIiwgc2VwPSJcdCIpCgp0b3RhbHJlYWRzPC1yZWFkLmNzdigiLi4vT3V0cHV0L0NOVi9yYXdSZWFkVG90YWxDb3VudF9wZXJTYW1wbGUuY3N2IikKbWluKHRvdGFscmVhZHMkcmF3VG90YWwpCm1lYW5Ub3RhbDwtYWdncmVnYXRlKHRvdGFscmVhZHMkcmF3VG90YWwsIGJ5PWxpc3QodG90YWxyZWFkcyRwb3ApLCBtZWFuKQpmb3IgKGogaW4gMTpsZW5ndGgoeTE3KSl7CiAgICBwbGlzdDwtcG9wc19pbmZvJFNhbXBsZVtwb3BzX2luZm8kUG9wdWxhdGlvbi5ZZWFyPT15MTdbal1dCiAgICBkZXB0aGxpc3Q8LWxpc3QoKQogICAgZm9yIChpIGluIDE6MTApewogICAgICAgIGRmPC1mcmVhZChwYXN0ZTAoIi4uL0RhdGEvYmFtX2RlcHRoL1BXU19vdmVybGFwL1kxNy8iLHBsaXN0W2ldLCJfb3ZlcmxhcHMudHh0Lmd6IikpCiAgICAgICAgdG90YWw8LXRvdGFscmVhZHMkcmF3VG90YWxbdG90YWxyZWFkcyRzYW1wbGU9PXBsaXN0W2ldXQogICAgICAgIGRmJFYzPC1kZiRWMy90b3RhbCoxMDAwMDAwMAogICAgICAgIHJlYWRzPC1saXN0KCkKICAgICAgICBmb3IgKGIgaW4gMTogbnJvdyhiZWQpKXsKICAgICAgICAgICAgZHA8LWRmW1YxPT1iZWQkVjFbYl0mIFYyPj1iZWQkVjJbYl0gJiBWMjw9IGJlZCRWM1tiXV0KICAgICAgICAgICAgCiAgICAgICAgICAgIGRwJHNhbXBsZTwtcGxpc3RbaV0KICAgICAgICAgICAgcmVhZHNbW2JdXTwtZHAKICAgICAgICB9CiAgICAgICAgZGVwdGhsaXN0W1tpXV08LXJlYWRzCiAgICAgICAgbmFtZXMoZGVwdGhsaXN0KVtpXTwtcGxpc3RbaV0KICAgIH0KICAgICNzYXZlUkRTKGRlcHRoX2xpc3QsZmlsZT1wYXN0ZTAoIi4uL091dHB1dC9DTlYvcGFpckNvbXAvUFdTX292ZXJsYXBfaW5kaXZpZHVhbF9kZXB0aC8iLCBwd3NsaXN0W2pdLCJfZGVwdGhzLlJEYXRhIikpCiAgICAKICAgICNmb3IgKGIgaW4gMjogbnJvdyhiZWQpKXsKICAgIGZvciAoYiBpbiA3OjcpCiAgICAgICAgZGF0YTwtbGFwcGx5KGRlcHRobGlzdCwgJ1tbJywgYikKICAgICAgICBkZXB0aHM8LWRvLmNhbGwocmJpbmQsZGF0YSkKICAgICAgICAjeW1heDwtaWZlbHNlKGI9PTd8Yj09NiwgNjAsIDMwKQogICAgICAgIGdncGxvdChkZXB0aHMsIGFlcyh4PVYyLCB5PVYzKSkrCiAgICAgICAgICAgIGZhY2V0X3dyYXAofnNhbXBsZSwgbmNvbD00KSsKICAgICAgICAgICAgZ2VvbV9wb2ludChzaXplPTAuMywgYWxwaGE9MC40LCBjb2xvcj0iIzAwOTZGRiIpKwogICAgICAgICAgICB5bGFiKCJSZWFkIGRlcHRoIikreGxhYigiIikrdGhlbWVfYncoKSsKICAgICAgICAgICAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSkreWxpbSgwLDcwKSsKICAgICAgICAgICAgZ2d0aXRsZShwYXN0ZTAoYmVkJFYxW2JdLCIgIixiZWQkVjJbYl0sIi0iLGJlZCRWM1tiXSkpCiAgICAgICAgICAgICNnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBub2J1ZmZlciRWMltiXSwgY29sb3I9ImdyYXk3MCIsIHNpemU9MC4zKSsKICAgICAgICAgICAgI2dlb21fdmxpbmUoeGludGVyY2VwdCA9IG5vYnVmZmVyJFYzW2JdLCBjb2xvcj0iZ3JheTcwIiwgc2l6ZT0wLjMpCiAgICAgICAgZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L0NOVi9wYWlyQ29tcC9QV1Nfb3ZlcmxhcF9pbmRpdmlkdWFsX2RlcHRoL1kxN19yZWdpb24iLGIsIi5ub3JtMTAuIix5MTdbal0sIi5wbmciKSwgd2lkdGggPSAxMiwgaGVpZ2h0PTcsIGRwaT0zMDApCiAgICAgICAgfQogICAgfQogICAgCiAgICAgICAgCn0KCgpmb3IgKGMgaW4gMToyNil7CiAgICBkZjE8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L0NOVi9wYWlyQ29tcC9ZMjAxNy9ydW5PdmVyNWsuWTE3LmNociIsYywiLmNzdiIpKQogICAgb3Y8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L0NOVi9wYWlyQ29tcC9ZMjAxNy9PdmVybGFwcGluZy5wb3NpdGlvbnMuWTE3LnJ1bk92ZXI1ay5jaHIiLGMsIi5jc3YiKSkKICAgIGRmPC1kZjFbZGYxJG51bWJlciAlaW4lIG92JG51bWJlcixdCiAgICBnZ3Bsb3QoZGYsIGFlcyh4PVYyLCB5PW1lYW4sIGNvbG9yPXBvcCkpKwogICAgICAgIGdlb21fcG9pbnQoc2l6ZT0wLjYsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMTAwMDAwKSwgYWxwaGE9MC41KSsKICAgICAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPW1lYW4tc2QsIHltYXg9bWVhbitzZCkscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxMDAwMDApLCB3aWR0aD0xMCwgc2l6ZT0wLjIpKwogICAgICAgIGdndGl0bGUocGFzdGUwKCJDaHIgIixjKSkrCiAgICAgICAgeGxhYigiIikreWxhYigibm9ybWFsaXplZCBtZWFuIHJlYWQgY291bnQgcGVyIDFrIHdpbmRvdyIpKwogICAgICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkreGxpbSgwLGNoc2l6ZSRWM1tjXSkrCiAgICAgICAgdGhlbWVfYncoKQogICAgZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L0NOVi9wYWlyQ29tcC9ZMjAxNy9PdmVybGFwcGluZ19zaXRlc19jaHIiLGMsIi5wbmciKSwgd2lkdGggPSAxMywgaGVpZ2h0PTMsIGRwaT0zMDApCn0KCmZvciAoaSBpbiAxOm5yb3coY29tYjIpKXsKICAgIHBvcDE8LWNvbWIyW2ksMV0KICAgIHBvcDI8LWNvbWIyW2ksMl0KICAgIG4xPC1ucm93KHBvcHNfaW5mb1twb3BzX2luZm8kUG9wdWxhdGlvbi5ZZWFyPT1wb3AxLF0pCiAgICBuMjwtbnJvdyhwb3BzX2luZm9bcG9wc19pbmZvJFBvcHVsYXRpb24uWWVhcj09cG9wMixdKQogICAgZm9yIChjIGluIDE6MjYpewogICAgICAgIGRmMTwtcmVhZC5jc3YocGFzdGUwKCIuLi9PdXRwdXQvQ05WL1JlYWROdW1iZXJfbm9ybWFsaXplZF8iLHBvcDEsICJfY2hyIixjLCIuY3N2IikpCiAgICAgICAgZGYyPC1yZWFkLmNzdihwYXN0ZTAoIi4uL091dHB1dC9DTlYvUmVhZE51bWJlcl9ub3JtYWxpemVkXyIscG9wMiwgIl9jaHIiLGMsIi5jc3YiKSkKICAgICAgICBjb21iZGY8LWNiaW5kKGRmMVssNDoobmNvbChkZjEpLTEpXSxkZjJbLDQ6KG5jb2woZGYyKS0xKV0pCiAgICAgICAgd2lsY294UmVzdWx0czwtYXBwbHkoY29tYmRmLCAxLCBmdW5jdGlvbih4KXsgd2lsY294LnRlc3QoeFsxOm4xXSx4WyhuMSsxKToobjErbjIpXSkgfSkKICAgICAgICBzaWc8LWxhcHBseSh3aWxjb3hSZXN1bHRzLGZ1bmN0aW9uKHgpIHt4PC11bmxpc3QoeCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHA8LXVubmFtZSh4WzJdKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuKGFzLm51bWVyaWMocCkpIH0pCiAgICAgICAgI2FkZCByb3cgbnVtYmVycyB0byBmaW5kIGNvbnNlY3V0aXZlIHdpbmRvd3MKICAgICAgICBkZjEkbnVtYmVyPC0xOm5yb3coZGYxKQogICAgICAgIGRmMiRudW1iZXI8LTE6bnJvdyhkZjIpCiAgICAgICAgI2NhbGN1bGF0ZSBTRCBmb3IgcGxvdHRpbmcKICAgICAgICBkZjEkc2Q8LWFwcGx5KGRmMVssYyg0OihuMSszKSldLCAxLCBzZCkKICAgICAgICBkZjIkc2Q8LWFwcGx5KGRmMlssYyg0OihuMiszKSldLCAxLCBzZCkKICAgICAgICAKICAgICAgICB0ZXN0PC1kZjFbLGMoIm51bWJlciIsIlYxIiwiVjIiLCJWMyIpXSAgICAKICAgICAgICB0ZXN0JHAudmFsdWU8LXVubGlzdChzaWcpCiAgICAgICAgdGVzdDwtdGVzdFt0ZXN0JHAudmFsdWU8PTAuMDEsXQogICAgICAgIHJlMTwtbWVyZ2UodGVzdCwgZGYxWyxjKCJudW1iZXIiLCJWMSIsIlYyIiwiVjMiLCJtZWFuIiwic2QiKV0pCiAgICAgICAgcmUyPC1tZXJnZSh0ZXN0LCBkZjJbLGMoIm51bWJlciIsIlYxIiwiVjIiLCJWMyIsIm1lYW4iLCJzZCIpXSkKICAgICAgICByZTEkcG9wPC1wb3AxCiAgICAgICAgcmUyJHBvcDwtcG9wMgogICAgICAgIHJlc3VsdHM8LXJiaW5kKHJlMSxyZTIpCiAgICAgICAgCiAgICAgICAgIyBGaW5kIGNvbnNlY3V0aXZlIHdpbmRvd3MKICAgICAgICByZTE8LXJlMVtvcmRlcihyZTEkbnVtYmVyKSxdCiAgICAgICAgYnJlYWtzPC1jKDAsIHdoaWNoKGRpZmYocmUxJG51bWJlcikgIT0gMSksbGVuZ3RoKHJlMSRudW1iZXIpKQogICAgICAgIHJ1bnBvczwtc2FwcGx5KHNlcShsZW5ndGgoYnJlYWtzKS0xKSwKICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgcmUxJG51bWJlclsoYnJlYWtzW3hdKzEpOmJyZWFrc1t4KzFdXSkKICAgICAgICBydW5wb3MzPC1GaWx0ZXIoZnVuY3Rpb24oeCkgYW55KGxlbmd0aCh1bmxpc3QoeCkpPj0zKSwgcnVucG9zKQogICAgICAgIHNhdmVSRFMocnVucG9zMyxmaWxlPXBhc3RlMCgiLi4vT3V0cHV0L0NOVi9wYWlyQ29tcC9jaHIiLGMsIl8iLHBvcDEsIi4iLHBvcDIsIl9jb25zZWN1dGl2ZVdpbmRvd3MuUkRhdGEiKSkKICAgICAgICAjIGZpbHRlciB0aGUgcmVzdWx0cyB0byBvbmx5IGNvbnNlY3RpdmUgcG9zaXRpb25zCiAgICAgICAgcG9zaXRpb25zPC11bmxpc3QocnVucG9zMykKICAgICAgICByZXN1bHRzPC1yZXN1bHRzW3Jlc3VsdHMkbnVtYmVyICVpbiUgcG9zaXRpb25zLF0KICAgICAgICAKICAgICAgICBwbG90czwtbGlzdCgpCiAgICAgICAgcGxvdHNbWzFdXTwtZ2dwbG90KHJlc3VsdHNbcmVzdWx0cyRWMzw9MTAwMDAwMDAsXSwgYWVzKHg9VjIsIHk9bWVhbiwgY29sb3I9cG9wKSkrCiAgICAgICAgICAgIGdlb21fcG9pbnQoc2l6ZT0wLjYsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42KSkrCiAgICAgICAgICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW49bWVhbi1zZCwgeW1heD1tZWFuK3NkKSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNiksIHdpZHRoPTAuMywgc2l6ZT0wLjIpKwogICAgICAgICAgICBnZ3RpdGxlKHBhc3RlMCgiQ2hyIixjKSkrCiAgICAgICAgICAgIHhsYWIoIiIpK3lsYWIoIm5vcm1hbGl6ZWQgbWVhbiByZWFkIGNvdW50IHBlciAxayIpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKwogICAgICAgICAgICB0aGVtZV9idygpCiAgICAgICAgcGxvdHNbWzJdXTwtZ2dwbG90KHJlc3VsdHNbcmVzdWx0cyRWMzw9MjAwMDAwMDAmcmVzdWx0cyRWMz4xMDAwMDAwMCxdLCBhZXMoeD1WMiwgeT1tZWFuLCBjb2xvcj1wb3ApKSsKICAgICAgICAgICAgZ2VvbV9wb2ludChzaXplPTAuNiwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpKSsKICAgICAgICAgICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1tZWFuLXNkLCB5bWF4PW1lYW4rc2QpLHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSwgd2lkdGg9MC4yLCBzaXplPTAuMikrCiAgICAgICAgICAgIGdndGl0bGUocGFzdGUwKCJDaHIiLGMpKSsKICAgICAgICAgICAgeGxhYigiIikreWxhYigibm9ybWFsaXplZCBtZWFuIHJlYWQgY291bnQgcGVyIDFrIikrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICAgICAgICAgIHRoZW1lX2J3KCkKICAgICAgICBwbG90c1tbM11dPC1nZ3Bsb3QocmVzdWx0c1tyZXN1bHRzJFYzPjIwMDAwMDAwLF0sIGFlcyh4PVYyLCB5PW1lYW4sIGNvbG9yPXBvcCkpKwogICAgICAgICAgICBnZW9tX3BvaW50KHNpemU9MC42LCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSkpKwogICAgICAgICAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPW1lYW4tc2QsIHltYXg9bWVhbitzZCkscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpLCB3aWR0aD0wLjIsIHNpemU9MC4yKSsKICAgICAgICAgICAgZ2d0aXRsZShwYXN0ZTAoIkNociIsYykpKwogICAgICAgICAgICB4bGFiKCIiKSt5bGFiKCJub3JtYWxpemVkIG1lYW4gcmVhZCBjb3VudCBwZXIgMWsiKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSsKICAgICAgICAgICAgdGhlbWVfYncoKQogICAgIAogICAgICAgIHtwZGYocGFzdGUwKCIuLi9PdXRwdXQvQ05WL3BhaXJDb21wL1kxNy8iLHBvcDEsIi4iLHBvcDIsIl9jaHIiLGMsIi5wZGYiKSwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gMTIpCiAgICAgICAgZG8uY2FsbChncmlkLmFycmFuZ2UsIGMocGxvdHMsIG5jb2w9MSkpCiAgICAgICAgZGV2Lm9mZigpfQogICAgICAgIAogICAgICAgIAogICAgfQp9CgoKCmBgYAoKCgoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI3Bsb3R0aW5nIAoKZm9yIChpIGluIDE6bnJvdyhjb21iKSl7CiAgICBwb3AxPC1jb21iW2ksMV0KICAgIHBvcDI8LWNvbWJbaSwyXQogICAgbjE8LW5jb2woZGYxKS00CiAgICBuMjwtbmNvbChkZjIpLTQKICAgIGZvciAoYyBpbiAxOjI2KXsKICAgICAgICBkZjE8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L0NOVi9SZWFkTnVtYmVyX25vcm1hbGl6ZWRfIixwb3AxLCAiX2NociIsYywiLmNzdiIpKQogICAgICAgIGRmMjwtcmVhZC5jc3YocGFzdGUwKCIuLi9PdXRwdXQvQ05WL1JlYWROdW1iZXJfbm9ybWFsaXplZF8iLHBvcDIsICJfY2hyIixjLCIuY3N2IikpCiAgICAgICAgY29tYmRmPC1jYmluZChkZjFbLDQ6KG5jb2woZGYxKS0xKV0sZGYyWyw0OihuY29sKGRmMiktMSldKQogICAgICAgIHdpbGNveFJlc3VsdHM8LWFwcGx5KGNvbWJkZiwgMSwgZnVuY3Rpb24oeCl7IHdpbGNveC50ZXN0KHhbMTpuMV0seFsobjErMSk6KG4xK24yKV0pIH0pCiAgICAgICAgc2lnPC1sYXBwbHkod2lsY294UmVzdWx0cyxmdW5jdGlvbih4KSB7eDwtdW5saXN0KHgpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwPC11bm5hbWUoeFsyXSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybihhcy5udW1lcmljKHApKSB9KQogICAgICAgIAogICAgICAgIGRmMSRudW1iZXI8LTE6bnJvdyhkZjEpCiAgICAgICAgZGYyJG51bWJlcjwtMTpucm93KGRmMikKICAgICAgICB0ZXN0PC1kZjFbLGMoIm51bWJlciIsIlYxIiwiVjIiLCJWMyIpXSAgICAKICAgICAgICB0ZXN0JHAudmFsdWU8LXVubGlzdChzaWcpCiAgICAgICAgdGVzdDwtdGVzdFt0ZXN0JHAudmFsdWU8PTAuMDEsXQogICAgICAgIGRmMSRzZDwtYXBwbHkoZGYxWyxjKDQ6KG5jb2woZGYxKS0xKSldLCAxLCBzZCkKICAgICAgICBkZjIkc2Q8LWFwcGx5KGRmMlssYyg0OihuY29sKGRmMiktMSkpXSwgMSwgc2QpCiAgICAgICAgcmUxPC1tZXJnZSh0ZXN0LCBkZjFbLGMoIm51bWJlciIsIlYxIiwiVjIiLCJWMyIsIm1lYW4iLCJzZCIpXSkKICAgICAgICByZTI8LW1lcmdlKHRlc3QsIGRmMlssYygibnVtYmVyIiwiVjEiLCJWMiIsIlYzIiwibWVhbiIsInNkIildKQogICAgICAgIHJlMSRwb3A8LXBvcDEKICAgICAgICByZTIkcG9wPC1wb3AyCiAgICAgICAgcmVzdWx0czwtcmJpbmQocmUxLHJlMikKICAgICAgICAKICAgICAgICAgIAogICAgICAgIHBsb3RzPC1saXN0KCkKICAgICAgICBwbG90c1tbMV1dPC1nZ3Bsb3QocmVzdWx0c1tyZXN1bHRzJFYzPD0xMDAwMDAwMCxdLCBhZXMoeD1WMiwgeT1tZWFuLCBjb2xvcj1wb3ApKSsKICAgICAgICAgICAgZ2VvbV9wb2ludChzaXplPTAuNiwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpKSsKICAgICAgICAgICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1tZWFuLXNkLCB5bWF4PW1lYW4rc2QpLHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSwgd2lkdGg9MC4yLCBzaXplPTAuMikrCiAgICAgICAgICAgIGdndGl0bGUocGFzdGUwKCJDaHIiLGMpKSsKICAgICAgICAgICAgeGxhYigiIikreWxhYigibm9ybWFsaXplZCBtZWFuIHJlYWQgY291bnQgcGVyIDFrIikrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICAgICAgICAgIHRoZW1lX2J3KCkKICAgICAgICBwbG90c1tbMl1dPC1nZ3Bsb3QocmVzdWx0c1tyZXN1bHRzJFYzPD0yMDAwMDAwMCZyZXN1bHRzJFYzPjEwMDAwMDAwLF0sIGFlcyh4PVYyLCB5PW1lYW4sIGNvbG9yPXBvcCkpKwogICAgICAgICAgICBnZW9tX3BvaW50KHNpemU9MC42LCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSkpKwogICAgICAgICAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPW1lYW4tc2QsIHltYXg9bWVhbitzZCkscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpLCB3aWR0aD0wLjIsIHNpemU9MC4yKSsKICAgICAgICAgICAgZ2d0aXRsZShwYXN0ZTAoIkNociIsYykpKwogICAgICAgICAgICB4bGFiKCIiKSt5bGFiKCJub3JtYWxpemVkIG1lYW4gcmVhZCBjb3VudCBwZXIgMWsiKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSsKICAgICAgICAgICAgdGhlbWVfYncoKSt5bGFiKDAsKQogICAgICAgIHBsb3RzW1szXV08LWdncGxvdChyZXN1bHRzW3Jlc3VsdHMkVjM+MjAwMDAwMDAsXSwgYWVzKHg9VjIsIHk9bWVhbiwgY29sb3I9cG9wKSkrCiAgICAgICAgICAgIGdlb21fcG9pbnQoc2l6ZT0wLjYsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSkrCiAgICAgICAgICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW49bWVhbi1zZCwgeW1heD1tZWFuK3NkKSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSksIHdpZHRoPTAuMiwgc2l6ZT0wLjIpKwogICAgICAgICAgICBnZ3RpdGxlKHBhc3RlMCgiQ2hyIixjKSkrCiAgICAgICAgICAgIHhsYWIoIiIpK3lsYWIoIm5vcm1hbGl6ZWQgbWVhbiByZWFkIGNvdW50IHBlciAxayIpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKwogICAgICAgICAgICB0aGVtZV9idygpCiAgICAgCiAgICAgICAge3BkZihwYXN0ZTAoIi4uL091dHB1dC9DTlYvcGFpckNvbXAvIixwb3AxLCIuIixwb3AyLCJfY2hyIixjLCIucGRmIiksIHdpZHRoID0gMTIsIGhlaWdodCA9IDEyKQogICAgICAgIGRvLmNhbGwoZ3JpZC5hcnJhbmdlLCBjKHBsb3RzLCBuY29sPTEpKQogICAgICAgIGRldi5vZmYoKX0KICAgICAgICAKICAgIH0KfQogICAgICAgIAogICAgCgoKCmBgYAoKCgoKCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKYGBgCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKYGBgCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKYGBgCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKYGBgCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKYGBgCgo=